vue2组件二次封装

发布时间 2023-11-16 14:43:10作者: 青云码上

有时候公共UI组件满足不了一些特定的需求样式,并且有较多地方使用同一个UI组件,这时候就需要考虑二次封装现有UI组件

组件二次封装关键的几点:

使用 $attrs 接收 props

使用 $listeners 接收事件

使用 $slots 和 $scopedSlots 接收插槽

使用model定义prop变量及其变化的事件(改变v-model的默认事件(input),同时避免表单校验时的交互bug)

覆盖原有事件(避免暴露出来的值变成[Object InputEvent])

 

以二次封装 a-input 为例:

my-input.vue

<template>
  <a-input v-bind="$attrs" v-on="new$listeners" :value="value">
    <!-- 遍历子组件非作用域插槽,并对父组件暴露 -->
    <template v-for="(index, name) in $slots" v-slot:[name]>
      <slot :name="name" />
    </template>
    <!-- 遍历子组件作用域插槽,并对父组件暴露 -->
    <template v-for="(index, name) in $scopedSlots" v-slot:[name]="data">
      <slot :name="name" v-bind="data"></slot>
    </template>
  </a-input>
</template>
<script>
export default {
  inheritAttrs: false, // 是否将继承的attribute设置到真实DOM上,这里没必要
  model: {
    prop: 'value',
    event: 'change' // 输入内容时,事件执行顺序为:chang =》 表单校验 =》 input, 所以这里不能写input,要写change
  },
  props: {
    value: [String]
  },
  data() {
    return {};
  },
  computed: {
    new$listeners() {
      return Object.assign(this.$listeners, {
        //在这里覆盖原有的 change 事件
        change: this.change
      });
    }
  },
  methods: {
    change(e) {
      this.$emit('change', e.target.value);
    }
  }
};
</script>

使用组件:

<PasswordInput
  v-model="form.aaa"
  @blur="inputBlur"
  @pressEnter="submit"
  size="large"
  placeholder="请输入"
/>