简介
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>