118 lines
3.0 KiB
Vue
118 lines
3.0 KiB
Vue
<script setup lang="ts">
|
|
const props = defineProps({
|
|
modelValue: { // v-model 默认接收的属性
|
|
type: [String, Number],
|
|
default: ''
|
|
},
|
|
clear: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
type: {
|
|
// 按钮类型
|
|
type: String,
|
|
default: 'text',
|
|
validator: (value: string) => ['text', 'password'].includes(value)
|
|
},
|
|
disabled: {
|
|
// 禁用
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
showPasswordOn: {
|
|
// 查看密码的事件
|
|
type: String,
|
|
default: 'click',
|
|
validator: (value: string) => ['click', 'mouseDown'].includes(value)
|
|
},
|
|
})
|
|
const emit = defineEmits([
|
|
'update:modelValue', // v-model 必须
|
|
'focus', // 聚焦事件
|
|
'blur' // 失焦事件
|
|
])
|
|
const inputRef = ref(null)
|
|
const clear = ref(props.clear)
|
|
const type = ref(props.type)
|
|
const disabled = ref(props.disabled)
|
|
const showPasswordOn = ref(props.showPasswordOn)
|
|
watchEffect(() => {
|
|
clear.value = props.clear;
|
|
type.value = props.type;
|
|
disabled.value = props.disabled;
|
|
showPasswordOn.value = props.showPasswordOn
|
|
})
|
|
// 输入事件处理
|
|
const handleInput = (event) => {
|
|
emit('update:modelValue', event.target.value)
|
|
}
|
|
|
|
// 聚焦事件透传
|
|
const handleFocus = (event) => {
|
|
emit('focus', event)
|
|
}
|
|
|
|
// 失焦事件透传
|
|
const handleBlur = (event) => {
|
|
emit('blur', event)
|
|
}
|
|
|
|
// 暴露方法(可选)
|
|
defineExpose({
|
|
focus: () => inputRef.value.focus(),
|
|
blur: () => inputRef.value.blur()
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div class="NiInput" data-prefix="Ni">
|
|
<div class="before">
|
|
<slot name="before"></slot>
|
|
</div>
|
|
<div class="inputMain">
|
|
<!-- 透传所有原生属性 v-bind="$attrs" -->
|
|
<input type="text" ref="inputRef"
|
|
class="ni-input"
|
|
:value="modelValue"
|
|
v-bind="$attrs"
|
|
@input="handleInput"
|
|
@focus="handleFocus"
|
|
@blur="handleBlur"></div>
|
|
<div class="show-password"></div>
|
|
<div class="after">
|
|
<slot name="after"></slot>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
.NiInput {
|
|
position: relative;
|
|
height: 100%;
|
|
|
|
& > div.inputMain {
|
|
position: relative;
|
|
width: 100%;
|
|
height: 100%;
|
|
display: flex;
|
|
align-items: center;
|
|
|
|
& > input {
|
|
height: 2rem;
|
|
width: 100%;
|
|
outline: none;
|
|
border: 1px solid var(--Ni-theme-border-color);
|
|
padding: .2rem .5rem;
|
|
border-radius: var(--Ni-border-radius);
|
|
box-sizing: border-box;
|
|
transition: border 0.3s ease-in-out;
|
|
font-size: 1rem;
|
|
font-family: v-sans, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
|
|
|
&:hover {
|
|
border-color: var(--Ni-theme-border-color-hover);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style> |