vue封装通用选择组件

2,105 阅读1分钟

之前拆解checkbox的v-model的时候,发现其实选择这类的可以统一抽象出来公共逻辑,这样可以脱离选项逻辑,用在任意项目 选择的样式可以灵活多变。

组件的源码

显示

<!-- SelectType.vue -->
<template>
  <div>
    <div class="option-box" @click="$refs.input.click()">
      <slot :isSelected="curChecked"></slot>
    </div>
    <!-- 原始input隐藏,这里的value看情况使用,可以不传,change是将选择事件抛出去,让父组件知晓 -->
    <input
      ref="input"
      hidden
      type="checkbox"
      :valueList="curChecked"
      :value="value"
      @change="changeInput($event)"
    />
  </div>
</template>
<script>
export default {
  // https://juejin.cn/post/6844904151856447495
  name: 'SelectType',
  model: {
    prop: 'valueList',
    event: 'change',
  },
  props: {
    isMultiple: {
      default: false,
    },
    // 整个选中的 值数组
    valueList: {
      required: true,
      default() {
        return [];
      },
    },
    // 选项的value值
    value: {
      required: true,
      default() {
        return '';
      },
    },
  },
  computed: {
    selectedList: {
      get() {
        return [...this.valueList];
      },
      set() {
        console.log();
      },
    },
    curChecked() {
      return this.valueList.includes(this.value);
    },
  },

  methods: {
    changeInput($event) {
      let { valueList } = $event.target;
      // 看下选中的值在数组中的索引,这里不用原生的value,因为$event.target.value始终是字符串类型
      let index = this.selectedList.indexOf(this.value);
      // 选择的时候,selectedList跟着变化
      if (this.isMultiple) {
        valueList
          ? this.selectedList.push(this.value)
          : index !== -1 && this.selectedList.splice(index, 1);
      } else {
        this.selectedList.length = 0;
        valueList && this.selectedList.push(this.value);
      }

      this.$emit('change', this.selectedList, $event);
    },
  },
};
</script>

组件的逻辑

主要用的是原始的checkbox。

  1. 当父组件传过来的checked是数组类型的时候,当前组件的初始状态curChecked是,看数组里有没有当前value,有就是选中,没有就不选中
  2. 数组是引用类型,为了不改变父组件的值,这里使用selectedList复制一份checked
  3. 当checkbox有change事件的时候,
  • 多选,选中就将value值push到selectedList,否则删掉,然后将selectedList抛给父组件
  • 单选,选中清空selectedList,valueList有的话直接将当前放进去
  1. !!! 注意这里使用computed,因为别的复选框选择的时候,selectedList也会跟着变化
  2. slot里面就是具体的dom了,此组件只提供逻辑

组件的使用步骤

使用方法:

  <SelectType v-model="valueCur" v-for="(item, index) in options" :key="index" :value="item.value" :isMultiple="isMultiple" > 
     <div class="option" :class="{selected:isSelected}" :text="item.text" slot-scope="{ isSelected }" :isSelected="isSelected" > {{item.text}} </div>
   </SelectType>

.option可以是任意复杂的dom,isSelected是当前项选中与否的值,这样可以灵活增加选中的样式 如果需要动态根据选中得到节点信息,可以加个监听事件 change

SelectType(v-model='selectedCodes' :value='item.code' @change='changeItem')
changeItem(...args){
    console.log(...args)
    // 两个值,第一个是选中的列表,第二个是原生input的信息
}