已解决:关于二次封装vue组件时,如何传递v-model,使得自定的二次封装组件拥有相同的v-model,甚至拥有相同的所有属性

可能做定制化开发的同学多少遇到过许多这种问题,就是自定义二次封装vue组件,前几天,试图封装一个vant的输入框,用来自定义一些聚焦和失去焦点时的不同样式,试了很久没有结果,主要是卡在了v-model无法传递这个点上了,苦思冥想加搜索,终于发现了解决之道。看正文:

第一部分:属性以及v-model

在进行Vue组件的二次封装时,如果想让v-model指令可用,需要在组件内部定义一个value属性和一个input事件,并将value属性绑定到子组件的某个属性上,同时在子组件的输入框上使用v-bind="$attrs"将父组件传递的所有属性绑定到子组件的输入框上,如下所示:

<!-- MyCustomInput.vue 子组件 -->
<template>
  <input type="text" v-bind="$attrs" v-model="internalValue" @input="$emit('input', $event.target.value)">
</template>

<script>
export default {
    
    
  name: 'MyCustomInput',
  props: {
    
    
    value: String // 父组件传递的 value 属性
  },
  data() {
    
    
    return {
    
    
      internalValue: this.value // 内部使用的 value 属性
    };
  },
};
</script>

在父组件中使用该自定义组件时,就可以像使用原生的元素一样使用v-model指令了,如下所示:

<!-- Parent.vue 父组件 -->
<template>
  <div>
    <my-custom-input v-model="message"></my-custom-input>
  </div>
</template>

<script>
import MyCustomInput from './MyCustomInput.vue';

export default {
    
    
  name: 'Parent',
  components: {
    
    
    MyCustomInput
  },
  data() {
    
    
    return {
    
    
      message: ''
    };
  }
};
</script>

在这个例子中,父组件中使用了v-model="message"指令来绑定数据到MyCustomInput组件中的value属性,该属性在子组件中使用了v-model="internalValue"指令进行绑定,并在input事件中通过$emit(‘input’, $event.target.value)事件将输入框的值传递给父组件。这样就实现了在自定义组件中使用v-model指令的功能。

第二部分:插槽和事件

讲到这里,就不得不说一下如何继承组件的插槽了,

插槽继承稍微麻烦一点,就是涉及多个插槽的时候,如何书写更加优雅,这里我不做不优雅的示范了,直接上优雅的干法:
下面是一个以 vant-field 标签为例的二次封装示例,演示如何继承原组件中的插槽,以二次封装vant-field标签为例:

<!-- MyCustomField.vue 子组件 -->
<template>
  <van-field
    v-bind="$attrs"
    v-model="value"
    v-on="$listeners"
  >
    <!-- 使用 $slots 继承原组件中的插槽 -->
    <template v-for="(_, name) in $slots" :slot="name" :key="name">
      <slot :name="name" />
    </template>
  </van-field>
</template>

<script>
import {
    
     Field } from 'vant';

export default {
    
    
  name: 'MyCustomField',
  components: {
    
    
    VanField: Field
  },
  props: {
    
    
    value: [String, Number],
    label: String,
    placeholder: String
  }
};
</script>

在这个示例中,我们首先通过 import 语句引入了 vant-field 组件,并在 components 选项中注册了该组件。然后,我们使用 v-bind=“ a t t r s " 将父组件中的所有属性和事件绑定到 v a n t − f i e l d 组件上,使用 v − m o d e l 将 v a l u e 绑定到 v a n t − f i e l d 组件的值上, ∗ ∗ 使用 v − o n = " attrs" 将父组件中的所有属性和事件绑定到 vant-field 组件上,使用 v-model 将 value 绑定到 vant-field 组件的值上,**使用 v-on=" attrs"将父组件中的所有属性和事件绑定到vantfield组件上,使用vmodelvalue绑定到vantfield组件的值上,使用von="listeners” 将父组件中的所有事件监听器绑定到 vant-field 组件上**。

最后,在 vant-field 组件中添加了一个使用 $slots 继承原组件中插槽的 块,遍历 $slots 特殊属性中的所有插槽,并将每个插槽的名称作为 slot 属性绑定到 vant-field 组件中,使用 元素将插槽继承到子组件中。

这样就可以在二次封装的 MyCustomField 组件中继承 vant-field 组件的所有插槽了。我们可以在使用 MyCustomField 组件时,像使用 vant-field 组件一样,添加任意数量的插槽,这些插槽都会被自动继承到 MyCustomField 组件中。同时也包含了所有的事件。

猜你喜欢

转载自blog.csdn.net/Spy003/article/details/130001444