element-ui 单选框radio组件源码分析,也是很常用的一个
单选框组件分为3部分
- radio-group: 单选组,适用于多个互斥的选项中选择的场景
- radio: 单选
- radio-button: 按钮样式的单选
2可以单独使用,也可与1组合使用,3和1要组合使用
radio-group
结构
很简单相当于是一个父容器,并且提供了键盘上下左右选中的方法
1 | <div |
slot接收的内容就是radio或radio-button了
script部分
1. 导入mixins
1 | import Emitter from 'element-ui/src/mixins/emitter'; |
这是其实就是用到emitter.js里的dispatch 方法(向上找到指定组件并发布指定事件及传递值)
1 | // 接收组件名,事件名,参数 |
在watch中监听value时用到
1 | watch: { |
2.声明 冻结上下左右的keyCode组成的对象
1 | const keyCode = Object.freeze({ |
Object.freeze() 方法可以冻结一个对象,冻结指的是不能向这个对象添加新的属性,不能修改其已有属性的值,不能删除已有属性,以及不能修改该对象已有属性的可枚举性、可配置性、可写性。该方法返回被冻结的对象。
3.若form-item组件注入属性影响size(默认为空)
1 | inject: { |
size在computed里
1 | // 最终大小 |
4.生命周期及watch
1 | created() { |
5.keyDown事件
1 | handleKeydown(e) { // 左右上下按键 可以在radio组内切换不同选项 |
switch case语句没有break默认向下执行,所以上左 和 下右 分别只写了一个执行函数和break(执行相同)
radio
结构
1.外层label,控制整体样式
1 | <label |
- role,aria-checked,aria-disabled三个属性是无障碍页面应用的属性(读屏软件会用到)参考
- tabindex: 属性规定元素的 tab 键控制次序 ,0为按照顺序,-1为不受tab控制
- @keydown.space:空格keydown事件(可查阅vue官网按键修饰符)
2.内层第一个span由span和不可见的input(模拟radio)组成(筛选框)
1 | <!-- 单选框 --> |
- aria-hidden:也是无障碍页面应用的属性(读屏软件会用到),为true时自动读屏软件会自动跳过,毕竟这是一个隐藏元素
3.内层第二个span显示(筛选框对应的内容)
1 | <!-- 单选文字 --> |
- $slots.default :接收匿名插槽内容
script部份
1.引入mixins
同上 用到的是mixins中的dispatch方法
1 | // 用到mixins中的dispatch方法,向上寻找对应的组件并发布事件 |
运用在input的change事件中
1 | handleChange() { |
- $nextTick: 将回调延迟到下次 DOM 更新循环之后执行
2.provide和 inject
1 | // form注入 |
同上,接收form组件注入属性,影响size及disabled。 (computed中可以看到)
3.computed
是否被radio-group包裹
1
2
3
4
5
6
7
8
9
10
11
12
13// 向上找radio-group组件 有则true无则false
isGroup() {
let parent = this.$parent;
while (parent) {
if (parent.$options.componentName !== 'ElRadioGroup') {
parent = parent.$parent;
} else {
this._radioGroup = parent;
return true;
}
}
return false;
}实现v-model
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// 实现v-model
model: {
// 取值
get() {
// radio-group的value或value
return this.isGroup ? this._radioGroup.value : this.value;
},
// 赋值
set(val) {
// 被radio-group组件包裹 radio-group组件发布input事件数组形式暴露值
if (this.isGroup) {
this.dispatch('ElRadioGroup', 'input', [val]);
} else {
// 没有被radio-group组件包裹,直接发布input事件暴露值
this.$emit('input', val);
}
}
}控制size,disabled,tabIndex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25_elFormItemSize() {
return (this.elFormItem || {}).elFormItemSize;
},
radioSize() {
// props的size及form注入的size及全局配置对象($ELEMENT,此对象由引入时Vue.use()传入的默认空对象)的size
const temRadioSize = this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
// 被radio-group组件包裹优先radioGroupSize
return this.isGroup
? this._radioGroup.radioGroupSize || temRadioSize
: temRadioSize;
},
isDisabled() {
// 被radio-group组件包裹,radioGroup的disabled || props的disabled || form注入的disabled,
// 未被radio-group组件包裹则少第一个条件
return this.isGroup
? this._radioGroup.disabled || this.disabled || (this.elForm || {}).disabled
: this.disabled || (this.elForm || {}).disabled;
},
// 控制tab是否可以选中
tabIndex() {
// 当tabindex=0时,该元素可以用tab键获取焦点,且访问的顺序是按照元素在文档中的顺序来focus
// 当tabindex=-1时,该元素用tab键获取不到焦点,但是可以通过js获取,这样就便于我们通过js设置上下左右键的响应事件来focus,在widget内部可以用到。
// 当tabindex>=1时,该元素可以用tab键获取焦点,而且优先级大于tabindex=0;不过在tabindex>=1时,数字越小,越先定位到。
return !this.isDisabled ? (this.isGroup ? (this.model === this.label ? 0 : -1) : 0) : -1;
}
radio-button
结构
与radio类似,label是button的样式,少了一个单选框的结构(span),input模拟radio并且不可见,另一个依旧是显示对应单选框内容的span
1 | <label |
script部分
逻辑与radio基本上一样,来看下有区别的地方
选中时的填充色和边框色
1 | computed: { |
- fill:是radio-group组件的属性(颜色)