Switch组件在分析的时候,主要需要关注三个点。如何实现自定义宽度、如何实现自定义背景颜色,以及html的整体架构。
<label class="el-switch">
<input type="checkbox" class="el-switch-input">
<span class="el-switch-core" ref="core">
<span class="el-switch-button" :style="buttonStyle"></span>
</span>
<transition name="label-fade">
<div class="el-switch-label el-switch-label-left">
</div>
</transition>
<transition name="label-fade">
<div class="el-switch-label el-switch-label-right">
</div>
</transition>
</label>
- 使用label包裹input, 利用了当选中label, input也会被选中的特性。这用即使隐藏了input, 使用label去“模拟”, 其实底层实质伤上,switch还是在操作这个input的value值。
- 因为按接口的文档,如果有文字就显示文字,如果有不同状态的图标就优先显示图标。所以这里就将这里边的逻辑单独提取到了switch-label里面。
后面就单独说几个Switch设计里面,我学到的东西
- 为什么要重新使用一个computed属性 _value
<input
type="checkbox"
class="el-switch-input"
v-model="_value"> //而不是传入的props: value
试了以后发现,Vue报了警告信息
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "value"
尽量避免直接去重写父组件中传入的props值,尝试使用computed属性。官方的说法是,这样随意的改变props,会让父子组件中的数据流变得非常的怪异和混乱。
平时都只是用到了computed的getter,但是,它是可以设置setter的!!!
computed: {
hasText: function () {
return this.onText || this.offText;
},
_value: {
get() {
return this.value;
},
set(val) {
this.$emit('input', val);
}
}
},
要看懂为什么使用$emit('input', val)就实现了_value的改变,就需要明白v-model的本质,这个语法糖的原理,以及v-bind和v-model有什么区别。
- 如何实现自定义宽度
利用一个data()属性 coreWidth, 加上mounted钩子函数,来初始化coreWidth
mounted() {
if(this.width === 0) {
this.coreWidth = this.hasText ? 58 : 46;
}
}
在core 和 switch-label上,都是通过:style动态设置宽度为coreWidth.
- 如何自定义背景颜色
当没有设置onColor或者offColor的时候,改变switch状态,input会根据checked与否来改变core的背景颜色和边框颜色。如果设置了onColor、offColor怎么办呢?
watch监听value值的变化。
watch: {
value() {
if(this.onColor || this.offColor) {
this.setBackgroundColor();
}
this.handleButtonTransform();
}
},
- 如何改变button圆圈的位置
因为不同的宽度,button的定位位置也不一样,js动态修改css值是肯定的。所以这里就和以前绑定类名这种不一样了,直接绑定一个style对象。
<span class="el-switch-button" :style="buttonStyle"></span>
handleButtonTransform() {
this.buttonStyle.transform = this.value ? `translate(${this.coreWidth - 20}px, 2px)`: 'translate(2px, 2px)';
},