checkbox

简介

1 .基本组件-多选框。主要用于一组可选项多项选择,或者单独用于标记切换某种状态
2 .v-model可以双向绑定
3 .使用CheckBoxGroup配合数组生成组合,实现多选
4 .

代码

<CheckBox 
 @click.prevent.native="handleCheckAll"
//父级组件定义了一个click事件,子组件里面有两个元素,span,input.都会触发这个事件,分别点击两个都是会有反应的。在这里我想要的target其实是input,这里需不需要做下检查
            
  :value="checkAll">全选:{{checkAll}}</CheckBox>

1 .checkbox.vue

<template>
    <label :class="wrapClasses">
        <span :class="checkboxClasses"> 
            <span :class="innerClasses">
            </span>
            <!-- 关键在这里,单个的话就直接绑定到外面,多个的话就转换成label绑定到本地的model里面,然后在提交到父里面的组件里面 -->
            <input 
                v-if="group"
                type="checkbox"
                :class="inputClasses"
                :disabled="disabled"
                :value="label"
                v-model="model"
                :name="name"
                @change="change"
                @focus="onFocus"
                @blur="onBlur"
                >
                <!-- 这种后绑定的值,v-model必须是个数组,不然只会拿到true或者false,拿不到新加的值 -->
            <input  
                    v-else
                    :class="inputClasses"
                    :disabled="disabled"
                    :name="name"
                    v-model='model'
                    @change="change"
                    @focus="onFocus"
                    @blur="onBlur"
                    type="checkbox"
                    >
        </span>
        <slot>
            <span v-if="showSlot">
                {{label}}
            </span>
        </slot>
    </label>
</template>
<script>
const pre="li-checkbox"
export default {
    name:'li-checkbox',
    props:{
        disabled:{
            type:Boolean,
            default:false,
        },
        value:{
            type:[String,Number,Boolean],
            default:false,
        },
        trueValue:{
            type:[String,Number,Boolean],
            default:true,
        },
        falseValue:{
            type:[String,Number,Boolean],
            default:false,
        },
        label:{
            type:[String,Number,Boolean]
        },
        indeterminate:{
            type:Boolean,
            default:false,
        },
        // 这个只是全选的时候加了一些样式吗?
        size:{
            validator(value){
                return ['small','large','default'].includes(value)
            },
            default:'default'
        },
        name:{
            type:String,
            default:'123'
        },
        border:{
            type:Boolean,
            default:false,
        }

    },
    data(){
        return {
            model:'',
            currentValue:this.value,
            group:false,
            parent:null,
            focusInner:false,
            showSlot:true,
        }
    },
    computed:{
        wrapClasses(){
            return[
                `${pre}-wrapper`,
                {
                    [`${pre}-group-item`]:this.group,
                    [`${pre}-wrapper-checked`]:this.model,
                    [`${pre}-wrapper-disabled`]:this.disabled,
                    [`${pre}-border`]:this.border,                
                }
            ]
        },
        checkboxClasses(){
            return [
                `${pre}`,
                {
                    [`${pre}-checked`]:this.model,
                    [`${pre}-disabled`]:this.disabled,
                    [`${pre}-indeterminate`]:this.indeterminate,
                }
            ]
        },
        innerClasses(){
            return [
                `${pre}-inner`,
                {
                    [`${pre}-focus`]:this.focusInner,
                }
            ]
        },
        inputClasses(){
            return `${pre}-input`
        },
    },
    mounted(){
        this.parent=this.$parent
        if(this.parent.$options.name=="li-checkbox-group"){
            this.group=true
        }

        // if(this.group){
        //     this.$parent.updateModel(true)
        // }else{
        //     this.updateModel()
        //     this.showSlot=this.$slots.default!==undefined
        // }

        this.updateModel()
        // this.showSlot=this.$slots.default!==undefined
    },
    methods:{
        change(e){
            if(this.disabled)return

            const checked=event.target.checked
            this.currentValue=checked

            const value=checked?this.trueValue:this.falseValue
            this.$emit('input',value)

            if(this.group){
                this.$parent.change(this.label)
            }else{
                this.$emit("on-change",value)
            }
        },
        updateModel(){
            this.currentValue=this.value===this.trueValue
        },
        onBlur(){
            this.focusInner=false
        },
        onFocus(){
            this.focusInner=true
        }
    },
    watch:{
        value(val){
            if(val===this.trueValue||val==this.falseValue){
                this.updateModel()
                this.model=val
            }else{
                console.warn("Value should be trueValue or falseValue")
            }
        }
    }
}
</script>
<style lang="less" src="./index.less">

</style>

2 .checkboxGroup.vue

<template>
    <div :class="classes">
        <slot></slot>
        {{value}}
    </div>
</template>
<script>
const pre='li-checkbox-group'
export default {
    name:'li-checkbox-group',
    props:{
        value:{
            type:Array,
            default(){
                return [];
            }
            // 理论上value是等于currentValues的,currentValues是往外面传递选择好的值
            // value是反向输入值,在获取外面输入的值进行双向绑定,根据外面的值,里面也要设置好这些状态
        },
        size:{
            validator(value){
                return ['small','large','default'].includes(value)
            },
            default(){
                // return !this.$IVIEW || this.$IVIEW.size === '' ? 'default' : this.$IVIEW.size;
                return 'default'
            },   
        }
    },
    data(){
            return {
                childrens:[],
                currentValues:[]
            }
    },
    computed:{
        classes(){
            return [
                `${pre}`,
                {
                    [`${pre}-${this.size}`]:!!this.size
                }
            ]
        }
    },
    methods:{
        change(data){    
            let index=this.currentValues.indexOf(data)
            if(index==-1){
                this.currentValues.push(data)
            }else{
                this.currentValues.splice(index,1)
            }

            this.$emit('input',this.currentValues)
            this.$emit('on-change',this.currentValues)
            // 改进一下版本
        },
        updateValue(value){
            // 根据外面的值进行操作
            if(value.length){
                 this.$children.forEach((e)=>{
                     if(value.includes(e.label)){
                         e.model=true
                     }
                 })
            }else{
                 this.$children.forEach((e)=>{
                     e.model=false
                })
            }
            
        }
    },
    watch:{
        value(v){
             this.updateValue(v)
             this.currentValues=v 
        },
        currentValues(v){
            this.updateValue(v)
        }
    }
}
</script>

3 .index.less

@import '../../assets/gLess.less';
@name:.li-checkbox;
@name2:.li-checkbox-group;

@{name}{
    display: inline-block;
    vertical-align: middle;
    white-space: nowrap;
    cursor: pointer;
    line-height: 1;
    position: relative;

    &-wrapper{
        cursor:pointer;
        font-size: @font-size-base;
        display: inline-block;
        margin-right: 8px;
    }

    &-disabled{
        cursor:@cursor-disabled;
        &@{name}-checked{
            &:hover{
                @{name}-inner{
                    border-color:@border-color-base;
                }
            }

            &@{name}-inner{
                background-color:#f3f3f3;
                border-color:@border-color-base;

                &:after{
                    animation-name:none;
                    border-color:#ccc;
                }
            }
        }

        &:hover{
            @{name}-inner{
                border-color:@border-color-base;
            }
        }

        @{name}-inner{
            border-color:@border-color-base;
            background-color:#f3f3f3;

            &:after{
                animation-name: none;
                border-color:#f3f3f3;
            }
        }

        @{name}-input{
            cursor: default;
        }

        &+span{
            color:#ccc;
            cursor: @cursor-disabled;
        }
    }

    &:hover{
        @{name}-inner{
            border-color:#bcbcbc;
        }
    }
    
    &-focus{
        box-shadow: 0 0 0 2px fade(@primary-color,20%);
        z-index:1;
    }

    &-input{
        margin:0;
        // 原本的checkbox会有margin属性,这里要把他清空
        width: 100%;
        height: 100%;
        position: absolute;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        z-index: 1;
        cursor: pointer;
        opacity: 0;
        &[disabled]{
            cursor:@cursor-disabled;
        };
    }

    &-inner{
        display: inline-block;
        width: 16px;
        height: 16px;
        position: relative;
        top: 0;
        left: 0;
        border:1px solid @border-color-base;
        border-radius: 2px;
        background-color: #fff;
        transition:border-color @transition-time @ease-in-out,background-color @transition-time @ease-in-out;

        &:after{
            content:'';
            display: inline-block;
            width: 4px;
            height: 4px;
            position: absolute;
            top:1px;
            left: 4px;
            border:2px solid #fff;
            border-top:0;
            border-left:0;
            transform:rotate(45deg) scale(0);
            // 一个只有右边和上边的正方形,大小是0
            transition:all @transition-time @ease-in-out;
        }
    }
    
    &-border{
        border:1px solid @border-color-base;
    }

    &-checked{
        @{name}-inner{
            border-color:@primary-color;
            background-color:@primary-color;

            &:after {
                content: '';
                display: table;
                width: 4px;
                height: 8px;
                // 宽度和高度发生变化,相当于拉长了对号
                position: absolute;
                top: 2px;
                left: 5px;
                border: 2px solid #fff;
                border-top: 0;
                border-left: 0;
                transform: rotate(45deg) scale(1);
                // 缩放从0变为1,实际显示为从小变大
                transition: all @transition-time @ease-in-out;
            }
        }
    }

    // 半选状态
    &-indeterminate{
        @{name}-inner:after{
            content:'';
            width: 10px;
            height: 0px;
            transform:scale(1);
            position: absolute;
            left: 2px;
            top: 6px;

        }

        &:hover{
            @{name}-inner{
                border-color:@primary-color;
            }
        }

        @{name}-inner{
            background-color:@primary-color;
            border-color:@primary-color;
        }
        &@{name}-disabled{
            @{name}-inner{
                background-color:#f3f3f3;
                border-color:@border-color-base;

                &:after{
                    border-color:@input-placeholder-color;
                }
            }

           
        }
    }
}

@{name2}{
    font-size:@font-size-base;

    &-item{
        display: inline-block;
    }
}

4 .使用代码

<template>
<!-- .native:监听根组件的本地事件 -->
<!-- .prevent: -->
    <div>
        <CheckBox 
            @click.prevent.native="handleCheckAll"
            :indeterminate="indeterminate"
            :value="checkAll">全选:{{checkAll}}</CheckBox>

        <CheckBoxGroup 
            @on-change="change"
            v-model="all">
            <CheckBox label="apple"></CheckBox>
            <CheckBox label="banana"></CheckBox>
            <CheckBox label="orange"></CheckBox>
        </CheckBoxGroup>
        <hr>
        {{checkAll}}
    </div>
</template>
<script>
import Radio from '../components/radio/'
import RadioGroup from '../components/radio/radio-group'
import CheckBox from '../components/checkbox/checkbox'
import CheckBoxGroup from '../components/checkbox/checkbox-group'
export default {
    components:{
        Radio,RadioGroup,CheckBox,CheckBoxGroup
    },
    data(){
        return {
            version:1,
            single:'',
            dev:'',
            all:[],
            checkAll:false,
            indeterminate:false,
        }
    },
    methods:{
        change(data){
            if(data.length==3){
                // 全选
                this.indeterminate=false
                this.checkAll=true

            }else if(data.length>0){
                // 部分选
                this.indeterminate=true
                this.checkAll=false

            }else{
                // 一个都没选
                this.indeterminate=false
                this.checkAll=false
            }
        },
        handleCheckAll(e){
            console.log(e.target)
            if(this.checkAll){
                console.log('1')
                this.all=[]
                this.checkAll=false
                this.indeterminate=false
            }else{
                this.all=['apple','orange','banana']
                console.log('2',this.all)
                this.checkAll=true
                this.indeterminate=false
            }
        }
    }
}
</script>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,386评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,142评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,704评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,702评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,716评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,573评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,314评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,230评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,680评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,873评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,991评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,706评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,329评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,910评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,038评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,158评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,941评论 2 355

推荐阅读更多精彩内容