将事件绑定到自定义组件

时间:2021-07-13 14:36:35

标签: vue.js vuejs3

使用 Vue3

我正在创建一个自定义组件并希望将事件绑定到其中的输入。所以在这种情况下,我想做一些与 v-bind="inputProps" 类似的事情。现在 $listeners 被删除了怎么办?正如您可能看到的,我无法使用 v-bind="$attrs",因为属性被划分为它们“去”的位置。

我是来解决问题的,但任何关于改进的提示总是值得欢迎的。

// c-text.vue

<template>
  <input
    v-if="useAsSingleElement"
    v-bind="inputProps"
    :class="['c-text', 'c-text--is-single-element']"
    @input="$emit('input', $event)"
    @blur="$emit('blur')"
    @focus="$emit('focus')">

  <c-form-item-shell
    v-else
    :id="id"
    :is-required="isRequired"
    :label-text="labelText"
    :icon="icon"
    :icon-class="iconClass"
    :errors="errors"
    :information="information">
    <template #element>
      <input
        v-bind="inputProps"
        class="c-text"
        @input="$emit('input', $event.target.value)"
        @blur="$emit('blur')"
        @focus="$emit('focus')">
    </template>
  </c-form-item-shell>
</template>

<script>
import { computed } from 'vue'
import CFormItemShell from '@/components/c-form-item-shell.vue'

export default {
  components: {
    CFormItemShell
  },
  props: {
    useAsSingleElement: { type: Boolean, required: false, default: false },
    name: { type: String, required: true },
    type: { type: String, required: false, default: 'text' },
    placeholder: { type: String, required: false, default: null },
    maxlength: { type: [String, Number], required: false, default: null },
    minxlength: { type: [String, Number], required: false, default: null },
    pattern: { type: String, required: false, default: null },
    readonly: { type: Boolean, required: false, default: false },
    spellcheck: { type: Boolean, required: false, default: false },
    autocomplete: { type: Boolean, required: false, default: true },
    id: { type: String, required: true },
    isRequired: { type: Boolean, required: false, default: false },
    labelText: { type: String, required: false, default: null },
    icon: { type: String, required: false, default: null },
    iconClass: { type: String, required: false, default: null },
    errors: { type: [String, Array], required: false, default: null },
    information: { type: [String, Array], required: false, default: null }
  },
  emits: ['input', 'blur', 'focus'],
  setup (props) {
    const inputProps = computed(() => {
      return {
        id: props.id,
        name: props.name ? props.name : props.id,
        type: props.type,
        placeholder: props.placeholder,
        maxlength: props.maxlength,
        minlength: props.minlength,
        pattern: props.pattern,
        readonly: props.readonly,
        spellcheck: props.spellcheck,
        autocomplete: props.autocomplete ? 'on' : 'off'
      }
    })

    return {
      inputProps
    }
  }
}
</script>

2 个答案:

答案 0 :(得分:1)

基于migration guide

<块引用>

在 Vue 3 的虚拟 DOM 中,事件侦听器现在只是属性,以 on 为前缀,因此是 $attrs 对象的一部分,因此 $listeners 已被删除。

所以只需传递您的事件,例如 onClickonBlur ... 和

export default {
  inheritAttrs: false
}

答案 1 :(得分:0)

回答我自己的问题和更详细的答案,希望它可以在未来帮助任何人。感谢 Boussadjra Brahim,他的回答让我开始思考。我做了以下

  1. 添加了inhertsAttrs: false
    Link to docs

这使得组件上的事件(意味着您的 @input@click 等)不会应用于父节点

  1. 添加了emits: ['update:modelValue', 'blur', 'focus']
    Link to docs

这应该是您想要捕获并发回的所有发射

  1. “收集”像这样手动发送到我的 propsAndListeners 对象。然后将其绑定到输入,如 <input v-bind="propsAndListeners" />

请记住,您必须使用 on 作为您的事件的前缀,因此如果您有一个 @click 事件,该事件将在 onClick 中具有名称 $attrs(@short是 v-on)

const propsAndListeners = computed(() => {
  return {
    onInput: (event) => emit('update:modelValue', event.target.value)
  }
})

在大多数情况下,您可能会将 $attrs 绑定到一个元素,但 propsAndListeners 的原因是我有 if 条件并且在两个地方为输入绑定了相同的内容.



这是完整的脚本部分

export default {
  components: {
    CFormItemShell
  },
  props: {
    useAsSingleElement: { type: Boolean, required: false, default: false },
    name: { type: String, required: true },
    type: { type: String, required: false, default: 'text' },
    modelValue: { type: [String, Number, Date], required: false, default: null },
    placeholder: { type: String, required: false, default: null },
    maxlength: { type: [String, Number], required: false, default: null },
    minxlength: { type: [String, Number], required: false, default: null },
    pattern: { type: String, required: false, default: null },
    readonly: { type: Boolean, required: false, default: false },
    spellcheck: { type: Boolean, required: false, default: false },
    autocomplete: { type: Boolean, required: false, default: true },
    id: { type: String, required: true },
    isRequired: { type: Boolean, required: false, default: false },
    labelText: { type: String, required: false, default: null },
    icon: { type: String, required: false, default: null },
    iconClass: { type: String, required: false, default: null },
    errors: { type: [String, Array], required: false, default: null },
    information: { type: [String, Array], required: false, default: null }
  },
  emits: ['update:modelValue', 'blur', 'focus'],
  setup (props, { emit }) {
    const propsAndListeners = computed(() => {
      return {
        id: props.id,
        name: props.name ? props.name : props.id,
        type: props.type,
        placeholder: props.placeholder,
        value: props.modelValue,
        maxlength: props.maxlength,
        minlength: props.minlength,
        pattern: props.pattern,
        readonly: props.readonly,
        spellcheck: props.spellcheck,
        autocomplete: props.autocomplete ? 'on' : 'off',
        onInput: (event) => emit('update:modelValue', event.target.value),
        onBlur: (event) => emit('blur', event),
        onFocus: (event) => emit('focus', event)
      }
    })

    return {
      propsAndListeners
    }
  }
}
相关问题