172 lines
3.5 KiB
Vue

<template>
<span class="p-input-wrapper"
:class="{'p-input-wrapper-group':($slots.prefix || $slots.suffix || type == 'password' ),'p-input-box-focus':state.focus}">
<span v-if="$slots.prefix" class="p-input-prefix"><slot name="prefix"/></span>
<input :type="inputType" @focus="state.focus = true"
@blur="state.focus = false"
:placeholder="placeholder"
v-model="value"
class="p-input" :class="{'p-input-box-focus':state.focus && !($slots.suffix || $slots.prefix)}">
<span v-if="$slots.suffix || type == 'password'" class="p-input-suffix">
<slot name="suffix"/>
<span v-if="type == 'password'" class="pointer-cursor" @click="state.passwordVisible = !state.passwordVisible">
<EyeClose v-if="state.passwordVisible"/>
<Eye v-else/>
</span>
</span>
</span>
</template>
<script lang="ts" setup>
import {computed, reactive, ref, useSlots} from "vue";
import Eye from "../icon/Eye.vue";
import EyeClose from "../icon/EyeClose.vue";
interface PInputEvents {
'update:modelValue': (value: any) => void
}
type PInputProps = {
placeholder?: string
modelValue?: any
type?: 'text' | 'password' | 'textarea'
}
const props = defineProps<PInputProps>()
const emit = defineEmits<PInputEvents>()
const slots = useSlots()
const state = reactive({
focus: false,
hover: false,
passwordVisible: false
})
const inputType = computed(() => {
const type = props.type || 'text';
if (type === 'password' && state.passwordVisible) return 'text';
return type;
})
const value = computed({
get() {
return props.modelValue
},
set(value) {
emit('update:modelValue', value)
}
})
</script>
<style lang="less">
@height: 30px;
.p-input-box-focus {
border-color: #2a7dc9;
box-shadow: 0 0 0 2px #0960bd33;
outline: 0;
}
.p-input {
box-sizing: border-box;
margin: 0;
list-style: none;
position: relative;
display: inline-block;
width: 100%;
min-width: 0;
padding: 4px 11px;
color: #000000d9;
font-size: 14px;
line-height: 1.5715;
background-color: #fff;
background-image: none;
border: 1px solid #d9d9d9;
border-radius: 2px;
transition: all .3s;
height: @height;
&::-moz-placeholder {
opacity: 1
}
&::placeholder {
color: #bfbfbf;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none
}
&:placeholder-shown {
text-overflow: ellipsis
}
&:hover {
border-color: #2a7dc9;
border-right-width: 1px !important
}
.p-input-rtl .p-input:hover {
border-right-width: 0;
border-left-width: 1px !important
}
&:focus, .p-input-focused {
border-right-width: 1px !important;
}
.p-input-disabled {
color: #00000040;
background-color: #f5f5f5;
border-color: #d9d9d9;
box-shadow: none;
cursor: not-allowed;
opacity: 1
}
}
.p-input-wrapper {
display: inline-block;
width: 100%;
}
.p-input-wrapper-group {
display: inline-flex;
position: relative;
max-width: 100%;
min-width: 0;
padding: 4px 6px;
color: #000000d9;
font-size: 14px;
line-height: 1.5715;
background-color: #fff;
background-image: none;
border: 1px solid #d9d9d9;
border-radius: var(--border-radius);
transition: all .3s;
height: @height;
&:hover {
border-color: #2a7dc9;
border-right-width: 1px !important
}
.p-input {
padding: 0;
border: none;
outline: none;
margin: 0 6px;
&:focus {
box-shadow: none;
}
}
}
.p-input-prefix, .p-input-suffix {
display: flex;
flex: none;
align-items: center;
}
</style>