vue checkbox简单组件

6,774 阅读3分钟

近期根据业务需要简单写了个checkbox及checkboxGroup组件,使用起来还算是方便,也顺便了解了下关于v-model的用法(可参考上一篇:v-model爬坑记录)。关于组件,也没什么特别复杂的,简单说下思路,直接上代码。

组件开发思路:

①、复选框从效果上看,就是是否勾选一些内容;从使用上来讲,我们需要将选中的选项对应的值传递出来,供后面使用。

②、基本的checkbox组件是基于input的checkbox开发的,同时为了样式相对统一将原来的input进行隐藏,通过css的  :checked 进行样式的统一。同时设置一些属性,比如是否是按钮形式、是否选中、是否不可点以及选项名称都做成可以配置的,方便后面使用。

③、对于单独一个的复选框方法比较简单,取到对应的值传到父组件即可;

④、对于多个复选框,我们将v-model绑定到了checkboxGroup组件上,对应的选中增加值、取消选中删除值方法也在父组件中,通过$emit在子组件中进行调用。

⑤、同时为了丰富使用场景,组件初始化的时候我们判断是否有默认选中的值,默认选中展示为勾选,同时将对应的值取出来进行收集。

这就是开发这个组件基本的一个思路,下面直接上代码,对应的属性方法都有注释,直接看注释就可以很清楚了。(关于文中样式使用的rem方法和@include方法,是通过sass统一定义的单位转换和字号转换方法,可根据实际情况进行修改)

基础的checkbox组件:

注:子组件的大盒子checkBoxClass实际可以去掉,这里主要是用来配置统一的文字颜色和字号,但是实际也只是基础的颜色,对于选中样式和选择框样式依旧需要通过样式覆盖方式进行修改。所以实际使用时关于样式我们可以通过样式覆盖的方式进行重置

<template> 
  <div class="checkbox" :class="checkBoxClass">
    <div :class="isDisable ? 'checkDisable' : ''">
      <div :class="isButton ? 'checkboxBtn' : 'checkboxItem'"> 
        <input type="checkbox" :value="val" :id="label" :checked="checked" :disabled="isDisable"  @change="checkChange($event)"/>        
        <label :for="label">{{ label }}</label>
      </div>
    </div>
  </div>
</template>

<script>
export default {  
  name: 'Checkbox',  
  model: {    prop: 'value',    event: 'change'  },  
  computed: {    
    /** 
      * 是否是复选框群组,通过父级ref是否为checkBigBox判断 
    */    
    isGroup() {
      return this.$parent.$refs && this.$parent.$refs.checkBigBox;    
    }  
  },  
  mounted() {
    /**     
      * 非多选组,并且初始为选中状态时,获取选中项的值     
      */    
    if (!this.isGroup) {      
      if (this.checked) {        
         this.$emit('change', this.val + '');      
      }    
    }  
  },  
  props: { 
    /**     
      * 外层盒子类名,可以通过属性传递配置,主要是修改文字颜色和字号。     
      * 如要修改选中样式、选择框颜色,可以通过样式覆盖方式,选中样式暂不考虑可以配置方式。     
    */    
    checkBoxClass: {
      type: String,     
      default: 'checkboxDefault'    
    },    
    /**     
      * 选择框是否是按钮形式,默认false     
     */    
    isButton: {      
      type: Boolean,      
      default: false    
    },    
    /**     
      * 选项名称     
      */    
    label: {      
      type: String,      
      default: '选项'    
    },   
    /**     
     * 选项值     
    */    
    val: {      
     type: [Number, String]    
    },    
    /**     
     * 初始化时是否选中状态,默认false     
    */    
    checked: {      
     type: Boolean,       
     default: false   
    },    
    /**     
     * 是否禁止选择,默认false     
    */    
    isDisable: {      
     type: Boolean,      
     default: false    
    }  
  },  
  methods: {    
    /**     
      * 点击checkbox时触发方法,多选组时调用父组件的增加和删除方法,单独复选框时设置值和清除值     
     */   
    checkChange(e) {      
      if (this.isGroup) {        
        if (e.target.checked) {          
          this.$parent.addCheck(e.target.value);        
        } else {          
          this.$parent.delCheck(e.target.value);        
        }      
      } else {        
        if (e.target.checked) {          
          this.$emit('change', e.target.value);        
        } else {          
          this.$emit('change', '');        
        }      
      }    
    }  
  }
};
</script>
<style lang="scss" scoped>
@import '../styles/mixins.scss';
.checkbox {  
  .checkboxItem { 
    margin: 0 rem(20) rem(20) 0;    
    input {      
      display: none;    
    }    
    label::before {     
      content: '√';      
      width: rem(28);      
      height: rem(28);      
      line-height: rem(28);      
      border: 1px solid #333;     
      display: inline-block;      
      text-align: center;      
      color: transparent;      
      margin-right: rem(6);    
    }    
    & input[type='checkbox']:checked ~ label {      
      color: #e20;    
    }    
    & input[type='checkbox']:checked ~ label::before {     
      content: '√';      
      color: #e20;      
      border: 1px solid #e20;    
    }  
  }  
  .checkboxBtn {    
    margin: 0 rem(20) rem(20) 0;    
    input {      
        display: none;    
    }    
    label {      
        position: relative;      
        padding: rem(4) rem(10);      
        display: block;    
    }    
    label::before {      
        content: '';      
        display: block;      
        width: 100%;      
        height: 100%;      
        border: 1px solid #333;      
        text-align: center;      
        color: transparent;      
        margin-right: rem(6);      
        position: absolute;      
        left: 0;      
        top: 0;    
    }    
    & input[type='checkbox']:checked ~ label {      
        color: #e20;    
    }    
    & input[type='checkbox']:checked ~ label::before {      
        content: '';      
        color: #e20;      
        border: 1px solid #e20;   
     }  
  }  
  .checkDisable {    
    .checkboxItem {      
        label {        
            color: #ccc;        
            cursor: not-allowed;      
        }      
        label::before {        
            content: '√';        
            border: 1px solid #ccc;       
             color: transparent;      
        }      
        & input[type='checkbox']:checked ~ label {       
             color: #ccc;     
         }     
        & input[type='checkbox']:checked ~ label::before {        
            content: '√';       
            color: #ccc;        
            border: 1px solid #ccc;      
        }    
    }    
    .checkboxBtn {      
        label {        
            color: #ccc;       
            cursor: not-allowed;      
        }      
        label::before {        
            content: '';        
            border: 1px solid #ccc;        
            color: transparent;      
        }      
        & input[type='checkbox']:checked ~ label {        
            color: #ccc;      
        }      
        & input[type='checkbox']:checked ~ label::before {        
            content: '';        
            color: #ccc;        
            border: 1px solid #ccc;      
        }    
    }  
  }
}
.checkboxDefault {  
    @include fontSize(24);  
    color: #333;
}
</style>

复选框组:

注:关于复选框组,其实我们并没有调用基础的checkbox,只是定义了一个大盒子,同时同slot占位。实际作用就是用来收集选中的数据以及处理复选框组对应的一些方法。

<template>  
    <div ref="checkBigBox" class="checkboxGroup">    
        <slot></slot>  
    </div>
</template>
<script>
export default {  
    name: 'CheckBoxGroup',  
    props: {    
        value: {      
            type: Array    
        }  
    },  
    model: {    
        prop: 'value',    
        event: 'change'  
    },  
    mounted() {    
        /**     
          * 多选组时,初始化如果有默认选中项则获取对应的value值     
         */    
        const childItem = this.$children;    
        let childArr = [];    
        childItem.map(child => {      
            if (child.checked) {        
                childArr.push(child.val + '');      
            }    
        });    
        this.$emit('change', [...childArr]);  
    },  
    methods: {    
        /**     
          * checkbox选中状态时,增加值方法     
          * 参数说明:    
          * @param {String} item 选中增加项的值    
         */    
        addCheck(item) {      
            const { value } = this;      
            this.$emit('change', [...value, item]);    
        },    
        /**     
          * checkbox取消选中状态时,减少值方法     
          * 参数说明:    
          * @param {String} item 取消选中项的值     
         */    
        delCheck(item) {      
            const { value } = this;      
            this.$emit('change', value.filter(val => val !== item));    
        }  
    }};
</script>
<style lang="scss" scoped>
.checkboxGroup {  display: flex;  flex-wrap: wrap;}
</style>

组件的使用:

/* 单独复选框使用 */
<Checkbox  :label="checkOne.label"  :val="checkOne.value"  :checked="checkOne.checked"  v-model="checkStr"></Checkbox>

/* 复选框组使用 */
<CheckBoxGroup v-model="checkBoxArr">  
    <Checkbox v-for="item in checkLists" :label="item.label" :val="item.value" :checked="item.checked" :isDisable="item.disable" :key="item.value" :checkBoxClass="checkBoxClass"></Checkbox>
</CheckBoxGroup>
<p>只有一项情况:{{ checkStr }}</p>
<p>复选框群组:{{ checkBoxArr }}</p>

data(){
    checkOne: { label: '手机', value: 10, checked: true },   
    checkLists: [       
        { label: '手机1', value: 0, disable: true },        
        { label: '电视', value: 1 },        
        { label: '洗衣机', value: 2, checked: true },        
        { label: '冰箱', value: 3 },        
        { label: '家用电器', value: 4, checked: true, disable: true },        
        { label: '手机2', value: 5 },        
        { label: '电视1', value: 6 },       
        { label: '洗衣机1', value: 7, checked: true },        
        { label: '冰箱1', value: 8 },        
        { label: '家用电器1', value: 9 }      
    ],  
    checkStr: '',  
    checkBoxArr: []
}

最终看下页面上展示的效果:


可以选择、取消,对应的灰色为不可修改选项。整体功能和方法都比较简单,样式方面使用时可以根据需求自己进行优化。

对于组件开发,个人觉得无论大小,对于基础和逻辑都是一个简单的锻炼过程,尤其是开发服用性较强的组件,对逻辑和使用场景的考虑需要更加全面。