Element(Vue 2.0)Switch 开关组件完全指南:从基础用法到源码级实现
【免费下载链接】elementA Vue.js 2.0 UI Toolkit for Web项目地址: https://gitcode.com/gh_mirrors/eleme/element
Element 是饿了么团队开源的 Vue.js 2.0 UI 组件库(仓库路径gh_mirrors/eleme/element),其中 Switch 开关组件用于在两个相互对立的状态(如「开/关」「按月/按年」)之间进行切换。本文以仓库中的官方文档(examples/docs/es/switch.md,同内容还提供 中文版 与 英文版)为核心骨架,结合组件源码、单元测试与主题样式,系统讲解el-switch的完整用法、全部属性/事件/方法与底层实现原理,帮助你既能在业务中熟练使用,也能深入理解其运行机制。
一、组件定位与适用场景
Switch 的本质是一个「二选一」的状态切换控件,常用于触发「开/关」等互斥操作。与 Checkbox 相比,Switch 更强调即时生效的动作语义(如开关某功能、切换计费方式),视觉上是一个可滑动的滑块。
在 Element 中,Switch 是一个独立的可安装组件,注册方式与其他组件一致,位于 packages/switch/index.js:
import Switch from './src/component'; Switch.install = function(Vue) { Vue.component(Switch.name, Switch); }; export default Switch;在模板中即可直接使用:
<el-switch v-model="value"></el-switch>二、基本用法:v-model 绑定与背景色定制
Switch 通过v-model绑定一个Boolean类型的变量,开启/关闭状态会自动同步回数据。默认开启状态为true、关闭状态为false。
官方文档(examples/docs/es/switch.md)给出的基本示例如下:
<el-switch v-model="value1"> </el-switch> <el-switch v-model="value2" active-color="#13ce66" inactive-color="#ff4949"> </el-switch> <script> export default { data() { return { value1: true, value2: true } } }; </script>其中:
v-model完成值的双向绑定;active-color指定「打开」状态的背景色(默认为主题色#409EFF);inactive-color指定「关闭」状态的背景色(默认为#C0CCDA)。
源码验证:颜色是如何生效的
在组件源码 packages/switch/src/component.vue 中,背景色通过setBackgroundColor方法写入内部核心滑块(.el-switch__core)的样式:
setBackgroundColor() { let newColor = this.checked ? this.activeColor : this.inactiveColor; this.$refs.core.style.borderColor = newColor; this.$refs.core.style.backgroundColor = newColor; }该方法在mounted时首次执行(前提是设置了activeColor或inactiveColor),并在checked状态变化的watch回调中再次执行,从而实现开/关切换时颜色的同步刷新。对应的单元测试(test/unit/specs/switch.spec.js)验证了activeColor="#0f0"、inactiveColor="#f00"时,核心元素的backgroundColor会随点击在绿/红之间正确切换。
三、文字描述:active-text 与 inactive-text
若希望开关两侧显示文字(如「按月付费 / 按年付费」),可使用active-text与inactive-text属性:
<el-switch v-model="value1" active-text="Pay by month" inactive-text="Pay by year"> </el-switch> <el-switch style="display: block" v-model="value2" active-color="#13ce66" inactive-color="#ff4949" active-text="Pay by month" inactive-text="Pay by year"> </el-switch> <script> export default { data() { return { value1: true, value2: true } } }; </script>从模板结构看文字渲染逻辑
在源码模板(packages/switch/src/component.vue)中,文字与图标被渲染为左右两个label区域:
<span :class="['el-switch__label', 'el-switch__label--left', !checked ? 'is-active' : '']" v-if="inactiveIconClass || inactiveText"> <i :class="[inactiveIconClass]" v-if="inactiveIconClass"></i> <span v-if="!inactiveIconClass && inactiveText" :aria-hidden="checked">{{ inactiveText }}</span> </span> <span class="el-switch__core" ref="core" :style="{ 'width': coreWidth + 'px' }"></span> <span :class="['el-switch__label', 'el-switch__label--right', checked ? 'is-active' : '']" v-if="activeIconClass || activeText"> <i :class="[activeIconClass]" v-if="activeIconClass"></i> <span v-if="!activeIconClass && activeText" :aria-hidden="!checked">{{ activeText }}</span> </span>关键细节:
- 关闭态文字(
inactive-text)显示在左侧(label--left),打开态文字(active-text)显示在右侧(label--right); - 通过
is-active类标记当前生效的文字,样式中生效侧文字使用主题色高亮(见 packages/theme-chalk/src/switch.scss); - 当设置了
active-icon-class/inactive-icon-class图标类时,优先渲染图标而忽略文字,两者互斥。
主题变量与尺寸
Switch 的尺寸与配色由主题变量控制,定义于 packages/theme-chalk/src/common/var.scss:
$--switch-on-color: $--color-primary !default; $--switch-off-color: $--border-color-base !default; $--switch-font-size: $--font-size-base !default; $--switch-core-border-radius: 10px !default; $--switch-width: 40px !default; $--switch-height: 20px !default; $--switch-button-size: 16px !default;滑块(.el-switch__core)的宽度通过内联样式:style="{ 'width': coreWidth + 'px' }"设置为width属性的值(默认 40px),高度固定 20px,圆形按钮直径 16px,滑块位移与颜色变化带有 0.3s 的过渡动画。源码中变量注释也指出:宽度在代码中写死为 40px 初始值,因此$--switch-width等变量实际意义有限,主题定制以width属性为主。
四、扩展 value 类型:active-value 与 inactive-value
默认情况下 Switch 的绑定值为Boolean。若业务需要,可设置active-value与inactive-value属性,二者接受Boolean、String或Number类型的值,使开关直接表达业务语义(如字符串'100'与'0')。
官方文档示例(结合 Tooltip 展示当前值):
<el-tooltip :content="'Switch value: ' + value" placement="top"> <el-switch v-model="value" active-color="#13ce66" inactive-color="#ff4949" active-value="100" inactive-value="0"> </el-switch> </el-tooltip> <script> export default { data() { return { value: '100' } } }; </script>源码验证:值切换与初始化矫正
组件内部通过checked计算属性判断当前是否处于「打开」状态:
computed: { checked() { return this.value === this.activeValue; }, ... }注意这里使用严格相等(===),因此active-value的类型必须与绑定值严格一致(例如都传字符串'100',而非字符串与数字混用)。
点击滑块时,handleChange依据当前状态切换到另一侧的值:
handleChange(event) { const val = this.checked ? this.inactiveValue : this.activeValue; this.$emit('input', val); this.$emit('change', val); ... }此外,created钩子会做一次初始化矫正:若初始绑定的value既不是activeValue也不是inactiveValue,则强制将值修正为inactiveValue:
created() { if (!~[this.activeValue, this.inactiveValue].indexOf(this.value)) { this.$emit('input', this.inactiveValue); } }对应的单元测试(expand switch value)验证了绑定'100'/'0'时,点击后值在'100'与'0'之间往返切换。
五、禁用状态:disabled
设置disabled属性后,Switch 进入禁用态,不再响应用户点击:
<el-switch v-model="value1" disabled> </el-switch> <el-switch v-model="value2" disabled> </el-switch> <script> export default { data() { return { value1: true, value2: false } } }; </script>源码验证:禁用是如何实现的
- 组件根节点在禁用时添加
is-disabled类(CSS 中表现为滑块与文字区域cursor: not-allowed、整体opacity: 0.6); switchDisabled计算属性同时考虑自身disabled与所在表单(elForm)的禁用状态,即外层el-form设置disabled时,内部 Switch 也会自动禁用:
computed: { switchDisabled() { return this.disabled || (this.elForm || {}).disabled; } }- 点击事件入口
switchValue会做守卫判断:!this.switchDisabled && this.handleChange(); - 内部隐藏的
<input type="checkbox">也会同步:disabled="switchDisabled"。
测试用例disabled switch should not respond to user click专门验证了禁用后点击滑块,绑定值保持不变。
六、完整的 Attributes / Events / Methods API
官方文档(examples/docs/es/switch.md)列出了完整的 API 表格,以下结合源码逐一补充默认值与类型约束。
Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
| value / v-model | 绑定值 | boolean / string / number | — | — |
| disabled | 是否禁用 | boolean | — | false |
| width | switch 的宽度(像素) | number | — | 40 |
| active-icon-class | switch 打开时所显示图标的类名,设置此项会忽略active-text | string | — | — |
| inactive-icon-class | switch 关闭时所显示图标的类名,设置此项会忽略inactive-text | string | — | — |
| active-text | switch 打开时的文字描述 | string | — | — |
| inactive-text | switch 关闭时的文字描述 | string | — | — |
| active-value | switch 打开时的值 | boolean / string / number | — | true |
| inactive-value | switch 关闭时的值 | boolean / string / number | — | false |
| active-color | switch 打开时的背景色 | string | — | #409EFF |
| inactive-color | switch 关闭时的背景色 | string | — | #C0CCDA |
| name | switch 对应的 name 属性 | string | — | — |
| validate-event | 改变 switch 状态时是否触发表单的校验 | boolean | — | true |
源码补充:在 packages/switch/src/component.vue 中,
name会透传到内部隐藏的<input>元素(<input ... :name="name">),因此 Switch 的值可以随表单提交;validate-event为true时,状态变化会通过dispatch('ElFormItem', 'el.form.change', [this.value])触发所在表单项的校验(组件混入了 src/mixins/emitter.js 的dispatch方法)。此外源码还额外支持文档表格之外的id属性(透传给内部 input)。对应的 TypeScript 类型声明见 types/switch.d.ts。
Events
| 事件名称 | 说明 | 回调参数 |
|---|---|---|
| change | switch 状态发生变化时的回调函数 | 新状态的值 |
change事件在handleChange中与input事件同时触发:this.$emit('input', val); this.$emit('change', val);。测试用例change event验证了点击滑块后回调能收到新的状态值。
Methods
| 方法名 | 说明 | 参数 |
|---|---|---|
| focus | 使 Switch 获取焦点 | — |
focus方法来自Focus('input')混入(见 src/mixins/focus.js),调用后会将焦点移到组件内部隐藏的<input>元素上,便于无障碍键盘操作(组件根节点声明了role="switch"、aria-checked与aria-disabled,并支持 Enter 键切换)。
七、无障碍与键盘交互细节
从模板可以看出,Switch 并非简单使用原生 checkbox 外观,而是「隐藏 input + 自绘滑块」的结构:
- 原生
<input type="checkbox">宽高为 0、完全透明(见 packages/theme-chalk/src/switch.scss 中.el-switch__input的样式),但保留name、disabled、checked等语义属性; - 根节点使用
role="switch"并维护aria-checked/aria-disabled; - 键盘聚焦 input 后按 Enter 键(
@keydown.enter="switchValue")即可切换状态。
八、数据流与「单一数据源」原则
Switch 遵循 Vue 单向数据流 +v-model约定:用户操作只负责发出input事件,最终展示状态永远以父组件的value为准。这一点在源码中有两处体现:
handleChange在$nextTick中重新将内部 input 的checked同步为this.checked,注释说明这是为了「防止父组件拒绝修改组件值」:
this.$nextTick(() => { if (this.$refs.input) { this.$refs.input.checked = this.checked; } });checked的watch回调同样会在值变化时同步 input 的checked与背景色。
测试用例value is the single source of truth专门验证:当父组件只传入:value="true"而不监听更新时,无论点击多少次,组件都保持选中态(is-checked类与 input.checked 均保持true);sets checkbox value则验证了外部修改v-model值会正确反映到内部 input 的checked状态。
九、图标开关与迁移兼容
Switch 支持在滑块两侧显示图标(如打勾el-icon-check与关闭el-icon-close):
<el-switch v-model="value" active-icon-class="el-icon-check" inactive-icon-class="el-icon-close"> </el-switch>设置图标类后,对应侧的文字描述会被忽略(模板中v-if="inactiveIconClass || inactiveText"与内部互斥判断)。测试用例switch with icons验证了.el-switch__label--left下会渲染包含el-icon-close类的<i>元素。
另外,组件通过getMigratingConfig(混入 src/mixins/migrating.js)在开发环境下提示旧版本属性改名:on-color→active-color、off-color→inactive-color、on-text→active-text、off-text→inactive-text、on-value→active-value、off-value→inactive-value、on-icon-class→active-icon-class、off-icon-class→inactive-icon-class。从旧版迁移到新版时按此对照表更新属性名即可。
十、样式定制建议
Switch 的视觉样式集中在 packages/theme-chalk/src/switch.scss,主题变量集中在 packages/theme-chalk/src/common/var.scss 的/* Switch */区块。主要定制点:
- 颜色:运行时通过
active-color/inactive-color属性覆盖;主题层面可覆盖$--switch-on-color、$--switch-off-color; - 尺寸:通过
width属性(number,单位 px)控制总宽度,高度与按钮直径由主题变量$--switch-height、$--switch-button-size控制; - 圆角与过渡:
$--switch-core-border-radius控制滑块圆角,.el-switch__core上定义了border-color .3s, background-color .3s的颜色过渡与.3s的按钮位移过渡。
结语
Element 的 Switch 组件虽然 API 简洁,但内部实现涵盖了 v-model 双向绑定、严格相等状态判断、值初始化矫正、表单联动校验、表单级禁用继承、无障碍键盘支持以及主题变量定制等多层设计。通过本文的「文档 + 源码 + 测试」三重对照,你可以在 examples/docs/es/switch.md、packages/switch/src/component.vue 与 test/unit/specs/switch.spec.js 之间自由穿梭,既快速上手,也能在需要深度定制时有的放矢。
【免费下载链接】elementA Vue.js 2.0 UI Toolkit for Web项目地址: https://gitcode.com/gh_mirrors/eleme/element
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考