vue封装复选框组件

前言

根据百度前端技术学院2018 MVVM 学院 中的 2.5 表单实现Input、Checkbox组件 用 vue 实现的

checkbox复选框组件,使checkbox有三种状态: checked:ture (选中) / false (未选中) , indeterminate (部分选中)

1.利用slot插槽

2.在同一文件中用到父子通信 $emit $on

本文章的 github地址


实现思路

1.在mounted(附加到页面上)时绑定监听

因为只有在mounted(元素挂载到页面上)之后才能理清节点之间的关系,也才能找到目标节点的$parent,$children

mounted() {
    // 得先检测其 $parent 是不是复选框组件(如果是,则其有onDispatch 函数)
    if (this.$parent.onDispatch) {
        // 如果组件的状态改变,则会执行其父组件的 onDispatch 函数
        this.$on("checkStatus", this.$parent.onDispatch);
    }
},

 

2. 当复选框状态改变时,将自己的改变后的复选框状态通知给其父复选框

this.$emit("checkStatus", "indeterminate"/true/false);

 

3. onDispatch 函数分析

3.1 接收到的值为 子组件状态改变后 发送过来的状态:{"indeterminate"/true/false}

3.2 改变其#(id).checked属性,直接操作其绑定的isChecked即可:checked="isChecked"

isChecked只有true/false 

3.3 改变其#(id).indeterminate属性,得获取元素(需要id,所以每个chekbox需要绑定一个id:id="id"),得到其indeterminate,

_getIndeterminate() {
    return document.getElementById(this.id).indeterminate;
},
_setIndeterminate(bool) {
    document.getElementById(this.id).indeterminate = bool;
},

 

3.4 当复选框状态为选中/未选中 时,设置其全部子组件为相对应值

(递归,多层改变,能对孩子,孙子,重孙等起作用。)

_setAllSubItem(component, bool) {
    component.$children.map(i => {
        i.isChecked = bool;
        this._setAllSubItem(i, bool);
    });
},

 

4. 最后执行形式

<v-checkbox text="爱好" id="hobby">
    <v-checkbox text="种花" id="plant">
        <v-checkbox text="养鱼" id="fish"></v-checkbox>
    </v-checkbox>
    <v-checkbox text="购物" id="shop"></v-checkbox>
    <v-checkbox text="吃饭" id="eat"></v-checkbox>
</v-checkbox>

 

代码实现

<template>
  <div>
    <label>
      <input type="checkbox" @change="handleChange" :checked="isChecked" :id="id">
      <span class="checkbox"></span>
      <span class="text" s-if="text">{{text}}</span>
    </label>
    <div class="sub">
      <slot></slot>
    </div>
  </div>
</template>
<script>
export default {
  props: ["text", "id"],
  mounted() {
    if (this.$parent.onDispatch) {
      this.$on("checkStatus", this.$parent.onDispatch);
    }
  },
  data() {
    return {
      id: this.id,
      parent: null,
      subItems: [],
      isChecked: false
    };
  },
  methods: {
    // 设置元素 Indeterminate 状态,若为true,表示部分选中
    _setIndeterminate(bool) {
      document.getElementById(this.id).indeterminate = bool;
    },

    // 获取元素 Indeterminate 状态
    _getIndeterminate() {
      return document.getElementById(this.id).indeterminate;
    },

    // 将元素所有子元素的选中状态统一设置成该元素的选中状态 true/false
    _setAllSubItem(component, bool) {
      component.$children.map(i => {
        i.isChecked = bool;
        this._setAllSubItem(i, bool);
      });
    },

    onDispatch(val) {
      //不是根元素
      // console.log(this.$parent.$parent._uid);
      console.log(this);
      // 恢复默认状态
      this._setIndeterminate(false);
      // 如果子组件传过来的值是"indeterminate",即子组件是部分选中状态,那么其父组件一定也是部分选中状态
      if (val == "indeterminate") {
        this._setIndeterminate(true);
        this.$emit("checkStatus", "indeterminate");
        return;
      }
      var subItems = this.$children;
      if (subItems.length > 0) {
        var check_num = 0;
        subItems.map(i => {
          // 或者如果子选项中有一个为indeterminate,那么其父组件也一定也是部分选中状态
          if (i._getIndeterminate()) {
            this._setIndeterminate(true);
            this.$emit("checkStatus", "indeterminate");
            return;
          }
          if (i.isChecked) {
            check_num++;
          }
        });
        if (check_num == subItems.length) {
          //选中子项目个数
          this.isChecked = true;
          this.$emit("checkStatus", true);
        } else if (check_num == 0) {
          this.isChecked = false;
          this.$emit("checkStatus", false);
        } else {
          this._setIndeterminate(true);
          this.$emit("checkStatus", "indeterminate");
        }
      }
    },

    handleChange() {
      this.isChecked = !this.isChecked;
      this.$emit("checkStatus", this.isChecked);
      if (this.isChecked) {
        this._setAllSubItem(this, true);
      } else {
        this._setAllSubItem(this, false);
      }
    }
  }
};

 

结束

如果文章对你有帮助,麻烦点赞哦!一起走码农花路~

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
单选框是前端展现数据字典的一种形式,下拉列表、单选按钮组和复选框组都可以实现。下拉列表是最常用的,但是单选按钮组也是一种常用的形式。下面介绍一下Vue组件单选框的封装方法。 单选框组件封装需要考虑以下几个方面: 1. 组件的props需要包含一个list属性,用于传递选项列表。 2. 组件的props需要包含一个modelValue属性,用于传递当前选中的值。 3. 组件需要在点击选项时,通过emit事件将选中的值传递给父组件。 4. 组件需要在选项列表中循环渲染每个选项,并且根据当前选中的值来设置选项的样式。 下面是一个简单的单选框组件的实现: <<引用>> 子组件: <template> <div class="radio-group"> <div v-for="(item, index) in props.list" :key="index" class="radio-item" :class="{active: item.value === props.modelValue}" @click="handleClick(item.value)"> <span>{{ item.label }}</span> </div> </div> </template> <script setup lang="ts"> import { defineProps, defineEmits } from 'vue' const props = defineProps({ list: { type: Array, required: true }, modelValue: { type: [String, Number], required: true } }) const emit = defineEmits(['update:modelValue']) const handleClick = (value: string | number) => { emit('update:modelValue', value) } </script> <style scoped> .radio-group { display: flex; flex-wrap: wrap; } .radio-item { margin-right: 10px; margin-bottom: 10px; padding: 8px 16px; font-size: 14px; background-color: #f6f7f9; border: 1px solid #f6f7f9; cursor: pointer; } .radio-item.active { background-color: var(--cp-plain); border-color: var(--cp-primary); } </style> 在父组件中使用该组件时,只需要传递一个选项列表和一个modelValue属性即可。例如: <template> <div> <radio-group :list="options" v-model="selected"></radio-group> </div> </template> <script> import RadioGroup from './RadioGroup.vue' export default { components: { RadioGroup }, data() { return { options: [ { label: '选项1', value: '1' }, { label: '选项2', value: '2' }, { label: '选项3', value: '3' } ], selected: '1' } } } </script>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值