可重复使用的输入组件,带有 vue 3 + typescript + Composition API
我有以下(atom)输入组件 Element UI(Element Plus for vue 3)作为基础组件。
atom/input/index.vue
<template>
<el-form-item :label="label">
<ElInput
:value="modelValue"
@input="$emit('update:modelValue', handleInputChange($event))"
>
<template v-if="prepend" #prepend>Http://</template>
<template v-if="append" #append>.com</template>
</ElInput>
</el-form-item>
</template>
<script setup lang="ts">
import { ElInput, ElFormItem } from "element-plus"
interface IInput {
label: string
modelValue: any
}
const { label, modelValue } = defineProps<IInput>()
const handleInputChange = (event: Event) => {
console.log(event)
return (event.target as HTMLInputElement).value
}
</script>
在我的主页组件中:
components/home.vue
<template>
<Input :label="'Book title'" v-model="title" />
<br/>
<h1>{{title}}</h1>
</template>
<script setup lang="ts">
import { ref } from "vue"
import Input from "./atom/input/index.vue"
const title = ref<string>("")
</script>
通过上述代码设置,组件以其标签以正确的形式显示。
但是当我开始在输入组件中输入时,控制台中出现以下错误。
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'value')
我还在控制台中记录了该事件,它返回了我输入的字符。
此外,我收到错误消息:
Argument of type 'string' is not assignable to parameter of type 'Event'.
在我的代码行中:
@input="$emit('update:modelValue', handleInputChange($event))"
我可以删除我的类型转换:
handleInputChange(<Event | unknown>$event)
我还尝试使用具有相同值的 html 输入标签创建可重复使用的输入组件并发出如上所述的内容,并且它没有任何错误地工作。
有人可以帮我找出我在这里遗漏了什么吗?
更新:
根据 Duannx 的建议,我更改了函数的返回值:
const handleInputChange = (event: any) => {
return event
}
但是现在,当我在输入字段中输入时,第一个字符被第二个字符替换,第二个字符被第三个字符替换,依此类推。
这是 element ui 游乐场中问题的重现:
我发现我必须在计算属性中使用 set 和 get 方法。
<template>
<el-form-item :label="label">
<ElInput
:autofocus="true"
:type="type"
:placeholder="placeholder"
:show-word-limit="showWordLimit"
:clearable="clearable"
:show-password="showPassword"
:suffix-icon="suffixIcon"
:prefix-icon="prefixIcon"
:size="size"
:max-length="maxLength"
v-model="val"
>
<template v-if="prepend" #prepend>Http://</template>
<template v-if="append" #append>.com</template>
</ElInput>
</el-form-item>
</template>
<script setup lang="ts">
import { computed, toRefs } from 'vue'
import { ElInput, ElFormItem } from "element-plus"
interface IInput {
label: string
type?: string
placeholder?: string
maxLength?: number
showWordLimit?: boolean
clearable?: boolean
showPassword?: boolean
suffixIcon?: any
prefixIcon?: any
size?: string
prepend?: any
append?: any
modelValue: any
}
const props = defineProps<IInput>()
const {
label,
type,
placeholder,
maxLength,
showWordLimit,
clearable,
showPassword,
suffixIcon,
prefixIcon,
size,
prepend,
append,
modelValue,
} = toRefs(props)
const emit = defineEmits(['update:modelValue'])
const val = computed({
get() {
return modelValue.value
},
set(val) {
emit('update:modelValue', val)
}
})
</script>
元素 plus input
的
input
事件传递的是一个值 (
string | number
),而不是
Event
类型。因此您可以直接使用
$event
作为值。
<ElInput
:value="modelValue"
@input="$emit('update:modelValue', $event)"
>
<template v-if="prepend" #prepend>Http://</template>
<template v-if="append" #append>.com</template>
</ElInput>
在您的 atom/input/index.vue 中,您只需传递 v-bind="$attrs"。$attrs 使 v-model、占位符和任何其他侦听器工作。v-bind="$attrs" 包括所有非 prop 属性
<ElInput v-bind="$attrs" />