Element Plus Switch 组件完全指南:从基础用法到源码级实现原理
2026/9/11 0:06:26 网站建设 项目流程

Element Plus Switch 组件完全指南:从基础用法到源码级实现原理

【免费下载链接】element-plus🎉 A Vue.js 3 UI Library made by Element team项目地址: https://gitcode.com/GitHub_Trending/el/element-plus

Element Plus 的ElSwitch组件用于在两个对立状态之间进行切换,是表单场景中最常用的开关控件之一。本文以 docs/en-US/component/switch.md 官方文档为骨架,结合 switch.vue 源码 与 switch.ts 类型定义,系统讲解其全部用法、API 属性、事件、插槽与底层实现原理,帮助你从"会用"进阶到"懂原理"。

基础用法(Basic usage)

Switch 通过v-model绑定一个Boolean类型的变量即可完成双向绑定,这也是最常用的场景。在 basic.vue 示例 中可以看到,开关打开与关闭两个状态下的背景色由两个 CSS 变量决定:

  • --el-switch-on-color:开启状态下的背景色
  • --el-switch-off-color:关闭状态下的背景色
<template> <el-switch v-model="value1" /> <el-switch v-model="value2" class="ml-2" style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949" /> </template> <script lang="ts" setup> import { ref } from 'vue' const value1 = ref(true) const value2 = ref(true) </script>

从样式源码 packages/theme-chalk/src/switch.scss 可以看到,当组件处于checked状态时,核心轨道(.el-switch__core)的background-color会取getCssVar('switch-on-color'),即--el-switch-on-color;未选中时背景色则为--el-switch-off-color。这两个 CSS 变量属于主题变量体系,既可以在组件内联样式覆盖,也可以在使用主题定制时全局调整。

底层模型:受控与非受控

从源码角度理解,model-valueactive-value/inactive-value的匹配关系决定了开关的显示状态。在 switch.vue 中:

const isControlled = ref(props.modelValue !== false) const actualValue = computed(() => { return isControlled.value ? props.modelValue : false }) const checked = computed(() => actualValue.value === props.activeValue)

checked的计算方式是严格相等比较:只有当当前值=== activeValue时开关才处于开启状态。同时,如果初始传入的model-value既不等于active-value也不等于inactive-value,源码会通过debugWarn输出警告,并自动将值矫正为inactiveValue

if (![props.activeValue, props.inactiveValue].includes(actualValue.value)) { debugWarn(COMPONENT_NAME, 'model-value must be active-value or inactive-value') emit(UPDATE_MODEL_EVENT, props.inactiveValue) // ... }

这说明在开发中务必保证绑定的值只来源于active-valueinactive-value二者之一,否则会收到警告并被强制归位。

尺寸(Sizes)

Switch 提供了largedefault(默认)、small三种尺寸,通过size属性控制,见 sizes.vue 示例:

<el-switch v-model="value" size="large" active-text="Open" inactive-text="Close" /> <br /> <el-switch v-model="value" active-text="Open" inactive-text="Close" /> <br /> <el-switch v-model="value" size="small" active-text="Open" inactive-text="Close" />

尺寸的取值在 switch.ts 中通过isValidComponentSize校验器约束,只允许'' | 'large' | 'default' | 'small'。需要注意的是,Switch 的size会通过useFormSize()与所在el-form/el-form-itemsize联动——当你设置了表单级尺寸而未显式指定 Switch 的size时,开关会自动继承表单的尺寸,这保证了表单内控件的一致性。

文字描述(Text description)

通过active-textinactive-text属性可以为开关两个状态分别添加文字说明。参见 text-description.vue 示例:

<el-switch v-model="value1" active-text="Pay by month" inactive-text="Pay by year" />

在默认(非inline-prompt)模式下,文字渲染在轨道两侧的独立标签区(.el-switch__label--left/--right);开启状态的文字在右侧、关闭状态的文字在左侧,并且只有当前生效的一侧文字处于激活高亮状态(源码中的labelLeftKls/labelRightKls通过ns.is('active', ...)控制)。

inline-prompt:文字内嵌进滑块

当希望文字直接显示在滑块内部时,使用inline-prompt属性。此时需要注意官方文档与源码的明确限制:

仅渲染文字的第一个字符。

从 switch.vue 的模板可以看到,inline-prompt模式下内容走的是.el-switch__inner结构,且官方示例(如active-text="完整展示多个内容")实际展示出的效果是首字 + 省略。因此若状态文字超过 1 个字符(如中文的"是/否"、英文的"Y/N"),可以放心使用;若必须展示完整文案,请使用非inline-prompt的轨道两侧模式。

自定义图标(Custom icons)

active-iconinactive-icon允许为开关两个状态指定图标,两者都会覆盖对应的文字属性(源码注释明确 "overridesactive-text" / "overridesinactive-text")。参见 custom-icons.vue 示例:

<script setup lang="ts"> import { ref } from 'vue' import { Check, Close } from '@element-plus/icons-vue' const value1 = ref(true) const value2 = ref(true) </script> <template> <el-switch v-model="value1" :active-icon="Check" :inactive-icon="Close" /> <el-switch v-model="value2" class="mt-2" style="margin-left: 24px" inline-prompt :active-icon="Check" :inactive-icon="Close" /> </template>

图标属性的取值类型为string | Component(即IconPropType,见 switch.ts),你可以:

  • 直接传入一个 SVG Vue 组件(如上例的Check/Close);
  • 传入一个已全局注册的组件名字符串。

Element Plus 内置了丰富的图标库,可前往 图标文档 挑选。模板中图标通过<el-icon>包装<component :is="...">渲染,因此在inline-prompt模式下图标也能完整显示在滑块内部,不受"仅渲染首字符"限制的影响。

扩展的值类型(Extended value types)

默认情况下开关绑定的是布尔值,但通过active-valueinactive-value,你可以让开关承载BooleanStringNumber任意一种类型的值。参见 extended-value-types.vue 示例:

<el-tooltip :content="'Switch value: ' + value" placement="top"> <el-switch v-model="value" style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949" active-value="100" inactive-value="0" /> </el-tooltip> <script lang="ts" setup> import { ref } from 'vue' const value = ref('100') </script>

此时v-model绑定的就不再是布尔值,而是开启时的"100"与关闭时的"0"。这与checked使用严格相等(===)比较的实现是配套的——类型必须完全一致才能正确匹配。在 switch.ts 中,activeValue默认trueinactiveValue默认false,类型均允许[Boolean, String, Number]

这一能力在表单提交场景非常实用,例如直接把开关值对应到接口约定的枚举字符串或数字,无需在提交前再做一次布尔到具体值的转换。

禁用状态(Disabled)

添加disabled属性即可禁用开关,见 disabled.vue 示例:

<el-switch v-model="value1" disabled /> <el-switch v-model="value2" class="ml-2" />

禁用后的开关透明度变为0.6(见 switch.scss)。值得注意的细节是,禁用状态并不仅仅是 UI 层面的:在 switch.vue 中,switchDisableduseFormDisabled计算得出,它会同时考虑:

  • 组件自身的disabled属性;
  • 所在el-form/el-form-item的禁用状态;
  • loading状态也会强制禁用开关

同时模板中的原生<input type="checkbox">也会同步设置:disabled="switchDisabled",保证键盘与鼠标都无法操作。

加载状态(Loading)

设置loading属性为true表示开关处于加载状态,见 loading.vue 示例:

<el-switch v-model="value1" loading /> <el-switch v-model="value2" loading class="ml-2" />

加载状态下,滑块(.el-switch__action)内部会渲染一个Loading旋转图标(<el-icon v-if="loading"><loading /></el-icon>),并且如上一节所述,开关会同时进入禁用态,避免用户在异步请求期间反复切换。loading通常与before-change配合使用——先置loadingtrue表示请求进行中,请求结束后再复位。

阻止切换(Prevent switching)

before-change属性允许在状态真正改变之前插入一道"审批关卡"。官方定义:返回false或返回一个被 reject 的Promise,都会阻止切换。参见 prevent-switching.vue 示例:

<script setup lang="ts"> import { ref } from 'vue' import { ElMessage } from 'element-plus' const value1 = ref(false) const value2 = ref(false) const loading1 = ref(false) const loading2 = ref(false) // 返回 true -> 允许切换 const beforeChange1 = (): Promise<boolean> => { loading1.value = true return new Promise((resolve) => { setTimeout(() => { loading1.value = false ElMessage.success('Switch success') return resolve(true) }, 1000) }) } // reject -> 阻止切换 const beforeChange2 = (): Promise<boolean> => { loading2.value = true return new Promise((_, reject) => { setTimeout(() => { loading2.value = false ElMessage.error('Switch failed') return reject(new Error('Error')) }, 1000) }) } </script> <template> <el-switch v-model="value1" :loading="loading1" :before-change="beforeChange1" /> <el-switch v-model="value2" class="ml-2" :loading="loading2" :before-change="beforeChange2" /> </template>

源码级的执行逻辑

before-change的判断逻辑在 switch.vue 的switchValue函数中:

const switchValue = () => { if (switchDisabled.value) return const { beforeChange } = props if (!beforeChange) { handleChange() return } const shouldChange = beforeChange() const isPromiseOrBool = [ isPromise(shouldChange), isBoolean(shouldChange), ].includes(true) if (!isPromiseOrBool) { throwError( COMPONENT_NAME, 'beforeChange must return type `Promise<boolean>` or `boolean`' ) } // ... }

关键点:

  1. 返回类型强校验beforeChange必须返回booleanPromise<boolean>,否则组件会直接throwError,属于运行时硬约束;
  2. Promise 语义resolve(true)才执行切换,reject会被捕获并debugWarn(不会导致未处理的 Promise 异常),而resolve(false)同样不切换;
  3. 同步 false:直接返回false也能立即阻止切换;
  4. handleChange()内部会依次发出update:model-valuechangeinput三个事件。

这种"先校验、后变更"的模式非常适合需要权限校验、余额确认、二次弹窗确认等业务场景。

自定义滑块图标(Custom action icon)^(2.3.9)

active-action-iconinactive-action-icon用于自定义滑块(action)内部显示的图标,与作用于轨道的active-icon/inactive-icon在视觉位置上不同。参见 custom-action-icon.vue 示例:

<script setup lang="ts"> import { ref } from 'vue' import { Hide, View } from '@element-plus/icons-vue' const value1 = ref(true) </script> <template> <el-switch v-model="value1" :active-action-icon="View" :inactive-action-icon="Hide" /> </template>

从 switch.vue 模板 可以看到.el-switch__action内的渲染优先级为:

loading(加载图标) > active-action / inactive-action 插槽 > action-icon 属性

即加载状态下始终显示 Loading 图标;否则优先使用插槽,其次才回退到active-action-icon/inactive-action-icon属性。

自定义滑块插槽(Custom action slot)^(2.4.4)

如果你需要的不是图标而是任意内容(如文字、徽标、自定义图形),可以使用active-actioninactive-action插槽。参见 custom-action-slot.vue 示例:

<el-switch v-model="value1"> <template #active-action> <span class="custom-active-action">T</span> </template> <template #inactive-action> <span class="custom-inactive-action">F</span> </template> </el-switch>

插槽内容将直接渲染在滑块内部,其尺寸受.el-switch__action样式(宽高均为滑块按钮尺寸)约束,因此自定义内容需要注意缩放与溢出控制。

完整 API 参考

以下 API 以 switch.md 官方文档为准,并结合 switch.ts 源码中的默认值与校验逻辑补充说明。

Attributes

属性名说明类型默认值
model-value / v-model绑定值,必须与active-valueinactive-value之一相等,默认布尔类型boolean / string / numberfalse
disabled是否禁用booleanfalse
loading是否处于加载状态(加载时同时禁用)booleanfalse
size开关尺寸'' / 'large' / 'default' / 'small'''(跟随表单上下文)
width开关宽度number / string''
inline-prompt图标或文字是否显示在滑块内部(文字仅渲染第一个字符)booleanfalse
active-icon开启状态图标,覆盖active-textstring / Component
inactive-icon关闭状态图标,覆盖inactive-textstring / Component
active-action-icon ^(2.3.9)开启状态滑块内图标string / Component
inactive-action-icon ^(2.3.9)关闭状态滑块内图标string / Component
active-text开启状态文字string''
inactive-text关闭状态文字string''
active-value开启状态对应的值boolean / string / numbertrue
inactive-value关闭状态对应的值boolean / string / numberfalse
name原生 input 的 name 属性string''
validate-event是否触发表单校验booleantrue
before-change状态改变前的钩子;返回false或返回被 reject 的Promise时阻止切换() => Promise<boolean> / boolean
id原生 input 的 idstring
tabindex原生 input 的 tabindexstring / number
aria-label ^(a11y) ^(2.7.2)同原生 input 的aria-labelstring
active-color ^(deprecated)开启状态背景色(已废弃,改用 CSS 变量--el-switch-on-colorstring''
inactive-color ^(deprecated)关闭状态背景色(已废弃,改用 CSS 变量--el-switch-off-colorstring''
border-color ^(deprecated)开关边框颜色(已废弃,改用 CSS 变量--el-switch-border-colorstring''
label ^(a11y) ^(deprecated)同原生 input 的aria-label已废弃,使用aria-labelstring

说明:width属性在源码中通过addUnit(props.width)注入.el-switch__corewidth内联样式(见 switch.vue),因此传60'60px'均合法;传入数值时宽度会随尺寸变大,文字区域会自动以省略号截断(示例中width="60"配合长文本即为该效果)。

Events

事件名说明回调参数
change值发生变化时触发(val: boolean / string / number) => void

从 switch.ts 可以看到,组件内部实际上声明了三个事件:update:model-valuechangeinput,三者都校验参数类型必须为boolean / string / number之一。其中change事件在handleChange中与update:model-valueinput一并触发,回调参数为切换后的新值(即activeValueinactiveValue)。

Slots

插槽名说明可用版本
active-action自定义开启状态下的滑块内容^(2.4.4)
inactive-action自定义关闭状态下的滑块内容^(2.4.4)
active自定义开启状态下的内容(轨道内/外由inline-prompt决定)^(2.13.0)
inactive自定义关闭状态下的内容^(2.13.0)

active/inactive插槽在模板中有两处消费:非inline-prompt时渲染在轨道两侧的标签区,inline-prompt时渲染在滑块旁的内部区域(见 switch.vue),因此可以通过这两个插槽在inline-prompt模式下绕过"仅首字符"限制。

Exposes

方法名说明类型
focus手动聚焦到开关组件() => void

focus()在源码中通过input.value?.focus?.()实现(见 switch.vue),配合模板中:focus-visible样式(见 switch.scss),键盘聚焦时滑块外层会出现--el-switch-on-color颜色的描边,保证可访问性。此外defineExpose还暴露了只读的checked计算属性,可直接通过 ref 判断开关当前是否处于开启状态。

无障碍与表单集成

从模板结构看(switch.vue),Switch 底层是一个不可见的原生<input type="checkbox">,并声明了role="switch"aria-checkedaria-disabledaria-label等 ARIA 属性,屏幕阅读器可以正确识别其开关语义。键盘上支持 Tab 聚焦与 Enter 键触发切换(@keydown.enter="switchValue")。

在表单场景中,Switch 通过useFormItemuseFormItemInputIdel-form-item深度集成:id 自动关联、禁用/尺寸自动继承、validate-event(默认true)在每次checked变化时触发formItem.validate('change'),因此不需要额外代码即可参与表单校验与 label 关联。

小结

Element Plus 的 Switch 组件在设计上兼顾了简单与灵活:

  • 开箱即用:默认布尔绑定即可满足绝大多数场景;
  • 值类型扩展active-value/inactive-value让开关可直接对接业务枚举值;
  • 状态控制disabledloadingbefore-change三层机制保障了异步与受限场景的正确性;
  • 视觉自定义:图标、文字、滑块内容、轨道颜色(CSS 变量)均可按需定制;
  • 可访问性:底层原生 checkbox + 完整 ARIA 语义,天然支持键盘操作与屏幕阅读器。

结合 switch.ts 与 switch.vue 的源码阅读,你不仅能准确使用每一个 API,还能理解"严格相等判状态、before-change 先行校验、三个事件同时触发"等底层约定,从而在复杂业务中做出正确的设计决策。

【免费下载链接】element-plus🎉 A Vue.js 3 UI Library made by Element team项目地址: https://gitcode.com/GitHub_Trending/el/element-plus

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询