简体   繁体   English

vue 3 + typescript + 组合 api 的可重用输入组件

[英]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 中问题的重现:

Demo url 演示 url

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM