3.23 Switch 开关

简介

开关选择器 Switch 用于表示开关状态/两种状态之间的切换时。本文将分析源码实现,耐心读完,相信会对您有所帮助。组件源码实现详见packages/switch/src/component.vue 。 🔗 组件文档 Switch 🔗 gitee源码 component.vue

组件checkbox单独使用可以表示两种状态之间的切换,和 switch 类似。两者在于切换 switch 会直接触发状态改变,而 checkbox 一般用于状态标记,需要和提交操作配合。

更多组件剖析详见 👉 📚 Element 2 源码剖析组件总览

源码实现

组件的 prop 声明,各属性功能说明详见 官方文档switch#attributes

组件的根节点是类名el-switch的div元素,内部有四个子元素:

  • type="checkbox"的input 元素。

  • 关闭时的图标/文字描述(左侧),类名el-switch__label--left的span 元素。

  • 组件核心,类名el-switch__core的span 元素。

  • 打开时的图标/文字描述(右侧),类名el-switch__label--right的span 元素。

<template>
  <div
    class="el-switch"
    :class="{ 'is-disabled': switchDisabled, 'is-checked': checked }"
    role="switch"
    :aria-checked="checked"
    :aria-disabled="switchDisabled"
    @click.prevent="switchValue"
  >
    <input class="el-switch__input" type="checkbox">
    <span  :class="['el-switch__label', 'el-switch__label--left']"></span>
    <span  class="el-switch__core" ref="core" ></span>
    <span  :class="['el-switch__label', 'el-switch__label--right']"></span> 
  </div>
</template>

组件页面渲染内容如下。 image.png

页面无法看到 input 元素,由其样式.el-switch__input可知宽/高/透明度都为0。页面无法聚焦到该元素。

根节点

根据组件的禁用状态以及打开状态绑定样式 is-disabledis-checked

计算属性checked判定组件是否打开状态。组件扩展的 value 类型,不仅支持boolean类型,也支持string/number。当使用string/number类型参数时, 需要手动设定activeValueinactiveValue属性值。

计算属性switchDisabled返回组件是否禁用。

添加点击事件@click="switchValue",用于实现组件点击后切换状态(当设置文字描述时,点击文字也能实现状态切换)。事件使用了修饰符 prevent,当触发的事件调用 event.preventDefault(),阻止自身默认事件的执行。

方法 switchValue 在非禁用状态下调用handleChange方法,实现开关状态的切换。

方法 handleChange中使用this.$emit('input', val);更新组件v-model值也就是value值。没有看到更新属性value值的操作。使用this.$emit('change', val);触发自定义状态变化事件。

组件使用v-model,需要使用$emit('input')来改变组件v-model值,否则无法更新用户传入的v-model值。 因为

属性 rolearia-checkedaria-disabled用于实现 ARIA无障碍网页应用。

状态描述

组件支持使用文字或者icon图标对状态进行描述。

组件左侧为关闭状态描述元素,只有设置了属性inactiveIconClassinactiveText才会显示。若设置属性inactiveIconClass会忽略 inactiveText

组件右侧为打开状态描述元素,实现逻辑请参考左侧分析。

组件核心

span元素是开关的外层容器,圆形滑块是由:after伪元素实现。

通过CSS设置高度、外边框圆角实现左右半圆效果。

定义打开状态下开关背景色。

圆形滑块使用绝对定位,使用 leftmargin-left定义打开状态下滑块位置(最右侧) 。 使用transition: all .3s定义了滑块动画时间以及背景颜色变化的时间。

属性 coreWidth 默认值为40。若设置了不同状态的开关背景色,在mounted中会调用方法setBackgroundColor。将元素样式border-colorbackground-color更新为当前状态设置的颜色。

input 元素

关于 input 元素的功能和使用场景无法准确分析推测。

文档中组件暴露出的 fous方法就是用于获取input元素的焦点 this.$refs["input"].focus()

将相关代码移除,组件也可正常运行。此处逻辑不做过多赘述!

拾遗

created中,进行了数值处理,若是v-model的值不是 activeValue inactiveValue任意属性值,使用$emit('input',val) 更新v-model值为inactiveValue ,让组件置位关闭状态。!~运算符让number转变成boolen类型。

当设置属性 validateEvent值为true 时,改变 switch 状态时是否触发表单的校验,触发组件 formItem 的方法 onFieldChange。具体校验逻辑等到组件Form 分析文章详细介绍。

组件样式

组件样式源码 packages\theme-chalk\src\switch.scss 使用混合指令 bewhenm 嵌套生成组件样式。

最后更新于