[英]Reusable input component with vue 3 + typescript + composition api
I have the following (atom) input component Element UI (Element Plus for vue 3) as base component.我有以下(atom)输入组件 Element UI(Vue 3 的 Element Plus)作为基本组件。
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>
In my home component:在我的家庭组件中:
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>
With the above code setup the component is displayed in correct form with its label.通过以上代码设置,组件以正确的形式显示,其 label。
But when I start typing in the input component I get the following error in my console.但是当我开始输入输入组件时,我在控制台中收到以下错误。
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'value')
未捕获(承诺)TypeError:无法读取未定义的属性(读取“值”)
I've also logged the event in the console and it is returning the characters that I've typed.我还在控制台中记录了该事件,它返回了我输入的字符。
Additionally I get error message of:此外,我收到以下错误消息:
Argument of type 'string' is not assignable to parameter of type 'Event'.
“字符串”类型的参数不可分配给“事件”类型的参数。
In my code line: @input="$emit('update:modelValue', handleInputChange($event))"
在我的代码行中:
@input="$emit('update:modelValue', handleInputChange($event))"
Which I was able to remove my typecasting: handleInputChange(<Event | unknown>$event)
我能够删除我的类型转换:
handleInputChange(<Event | unknown>$event)
I also tried creating reusable input component with html input tag with same value and emit as above and it worked without any error.我还尝试使用具有相同值的 html 输入标签创建可重复使用的输入组件,并像上面那样发出,并且它没有任何错误地工作。
Can anyone help me figure out what I'm missing here?谁能帮我弄清楚我在这里缺少什么?
Update:更新:
As suggestion by Duannx I changed my return of the function:根据Duannx的建议,我更改了 function 的返回值:
const handleInputChange = (event: any) => {
return event
}
But now when I type in the input field the first character is replaced by second character, second character is replaced by third and so on.但是现在,当我在输入字段中键入时,第一个字符将替换为第二个字符,第二个字符将替换为第三个,依此类推。
Here is the reproduction of the issue in element ui playground:这是 element ui playground 中问题的重现:
The input
event of the element plus input is passed a value ( string | number
), not an Event
type. 元素加上输入的
input
事件传递的是一个值( string | number
),而不是一个Event
类型。 So you can use $event
directly as the value.所以你可以直接使用
$event
作为值。
<ElInput
:value="modelValue"
@input="$emit('update:modelValue', $event)"
>
<template v-if="prepend" #prepend>Http://</template>
<template v-if="append" #append>.com</template>
</ElInput>
I figured out that I have to make use of set and get method in computed property.我发现我必须在计算属性中使用 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>
In your atom/input/index.vue all you have to pass is the v-bind="$attrs".在你的 atom/input/index.vue 中,你只需要传递 v-bind="$attrs"。 The $attrs makes the v-model, placeholder, and any other listener works.
$attrs 使 v-model、占位符和任何其他侦听器工作。 v-bind="$attrs" includes all non-prop attributes
v-bind="$attrs" 包括所有非 prop 属性
<ElInput v-bind="$attrs" />
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.