_index.js
import ElCheckbox from './src/checkbox';
import ElCheckboxGroup from './src/checkbox-group.vue';
export default function install(Vue) {
Vue.component(ElCheckboxGroup.name, ElCheckboxGroup);
Vue.component(ElCheckbox.name, ElCheckbox);
};
export {
ElCheckbox,
ElCheckboxGroup
};
Checkbox-group
<template>
<div class="el-checkbox-group">
<slot></slot>
</div>
</template>
checkbox-group
的html
代码十分简单,就是一个div.el-checkbox-group
包裹着一个slot
,没有什么好说的,但是它在script
里面做了许多处理。
Watch
监听value
的变化,然后会触发一个change
事件,并且根据mixin
中的emitter
增加的dispatch
来向父组件派发事件。
watch: {
value(value) {
this.$emit('change', value);
this.dispatch('ElFormItem', 'el.form.change', [value]);
}
}
dispatch
具体的讲解将在mixin篇
进行讲解,简单的说是模拟vue 1.0
中的$dispatch
,来将事件一直向上传递。
mixins: [Emitter],
Checkbox
我们还是先分析其生命周期。
生命周期
created
创建的时候根据checked
这一prop
来决定是否调用addToStore
方法,
methods: {
addToStore() {
if (
Array.isArray(this.model) &&
this.model.indexOf(this.label) === -1
) { // 如果 model 是数组,且不包含 label,就加入label
this.model.push(this.label);
} else { // 否则 model 设置为 trueLabel或者 true
this.model = this.trueLabel || true;
}
}
},
checkbox
组件一共有三种label
,这里先列一下官方的说明,具体使用在接下来的分析中会提及:
-
label
,选中状态的值(只有在checkbox-group
或者绑定对象类型为array
时有效),它的值是string
; -
true-label
,选中时的值,它的值是string
或者number
; -
false-label
,没有选中时的值,它的值是string
或者number
。
而model
是一个计算属性:
computed: {
model: {
get() { // 取值
return this.isGroup
? this.store : this.value !== undefined // 多选组的时候,返回store
? this.value : this.selfModel; // 否则,如果 value 不是未定义,返回 value,要么返回selfModel
},
set(val) { // 赋值
if (this.isGroup) { // 如果是多选组
this.dispatch('ElCheckboxGroup', 'input', [val]); // 向父组件派发事件
} else if (this.value !== undefined) { // value 不是未定义
this.$emit('input', val); // 触发 input 事件
} else { // 其它
this.selfModel = val; // 设置selfModel
}
}
},
其中value
是一个prop
,而selfModel
是一个data
上的属性,store
是一个计算属性:
computed: {
store() {
// 如果父组件是多选组,则返回它的value,否则返回当前多选的 value
return this._checkboxGroup ? this._checkboxGroup.value : this.value;
}
}
而isGroup
是另一个计算属性,它将一直向父级查找到el-checkbox-group
,如果有则返回true
,否则返回false
:
computed: {
isGroup() {
let parent = this.$parent;
while (parent) {
if (parent.$options.componentName !== 'ElCheckboxGroup') {
parent = parent.$parent;
} else {
this._checkboxGroup = parent;
return true;
}
}
return false;
},
}
label
多选最外面是一个label
。
<label class="el-checkbox">
</label>
然后是两个span
,一个是input
部分,另一个是label
部分。
el-checkbox__input
el-checkbox__input
最外层也是一个span
,并在上面设置了动态的class
:
<span class="el-checkbox__input"
:class="{
'is-disabled': disabled, // 这是prop,控制是否可用
'is-checked': isChecked, // 这是一个计算属性
'is-indeterminate': indeterminate, // 这是prop,用来控制样式
'is-focus': focus // 这是data属性,用来控制是否聚焦
}"
>
</span>
其中isChecked
的设置如下:
computed: {
isChecked() {
if ({}.toString.call(this.model) === '[object Boolean]') { // 如果 model 是布尔型
return this.model; // 直接返回 model
} else if (Array.isArray(this.model)) { // 如果 model 是数组
return this.model.indexOf(this.label) > -1; // 返回其中是否包含 label
} else if (this.model !== null && this.model !== undefined) { // 如果 model 不是null,也不是 undefined
return this.model === this.trueLabel; // 返回 model 是否完全等价于 trueLabel
}
},
}
el-checkbox__inner
然后是用来表示前面对勾的span
,它 主要通过css
来控制对勾的显示。
<span class="el-checkbox__inner"></span>
input
然后是传统的input
,它的type
是checkbox
,但是这个input
并不会显示,而且会根据传递的prop
有两种不同的input
。
<input
v-if="trueLabel || falseLabel"
class="el-checkbox__original"
type="checkbox"
:name="name"
:disabled="disabled"
:true-value="trueLabel"
:false-value="falseLabel"
v-model="model"
@change="$emit('change', $event)"
@focus="focus = true"
@blur="focus = false">
<input
v-else
class="el-checkbox__original"
type="checkbox"
:disabled="disabled"
:value="label"
:name="name"
v-model="model"
@change="$emit('change', $event)"
@focus="focus = true"
@blur="focus = false">
它们不同的地方是,前者使用了trueLabel
和falseLabel
,后者使用了label
它们都通过v-model
绑定了model
,在change
的时候都会派发change
事件,聚焦的时候会设置focus
为true
,
el-checkbox__label
标签部分可以通过匿名slot
或者label
进行设置,前者具有优先权。
<span class="el-checkbox__label" v-if="$slots.default || label">
<slot></slot>
<template v-if="!$slots.default">{{label}}</template>
</span>
```
> 注:这里明显看出来,这和之前不是同一个人写的,这里值得注意的是`slot`内部的内容,在没有传入`slot`才会显示,因此不同特别做一个处理,也可能是有其他我没有考虑到的原因,如果以后发现了,会回来修正。