欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > 【ElementPlus源码】Switch开关

【ElementPlus源码】Switch开关

2024/10/23 22:56:11 来源:https://blog.csdn.net/karshey/article/details/142940410  浏览:    关键词:【ElementPlus源码】Switch开关

文章目录

    • 基础用法 modelValue
    • 尺寸 size
    • 文字描述与自定义图标
    • 扩展的 value 类型
      • isControlled 是否受控
      • actualValue 实际值
      • checked 开关状态
    • 禁用状态、加载状态
    • 阻止切换 beforeChange
    • 切换 handleChange

看源码时候做的笔记。
Switch 开关 | Element Plus (element-plus.org)

基础用法 modelValue

在vue3中,v-modelmodelValue绑定的是同一个值。
v-model是一个语法糖,等同于同时使用:modelValue@update:modalValue,即向子组件传递一个名为modelValue的prop,同时监听一个名为update:modelValue的事件。

基础用法:绑定 v-model 到一个 Boolean 类型的变量。 会传到prop的modelValue中。

modelValue: {type: [Boolean, String, Number],default: false,},

尺寸 size

会传到prop的size中,是枚举值。

文字描述与自定义图标

  • active-text
  • inactive-text
  • inline-prompt

分别表示开关文案、控制文本是否显示在点内。源码中是驼峰式的,主要通过条件渲染实现。

  • inactive-icon
  • active-icon

开关icon。条件渲染实现。

扩展的 value 类型

  • activeValue
  • inactiveValue

绑定的开/关的对应值,类型可以为:Boolean, String, Number。

/*** @description switch value when in `on` state*/activeValue: {type: [Boolean, String, Number],default: true,},/*** @description switch value when in `off` state*/inactiveValue: {type: [Boolean, String, Number],default: false,},

switch开关底层是一个vue的input checkbox控件:

 <input:id="inputId"ref="input":class="ns.e('input')"type="checkbox"role="switch":aria-checked="checked":aria-disabled="switchDisabled":aria-label="label || ariaLabel":name="name":true-value="activeValue":false-value="inactiveValue":disabled="switchDisabled":tabindex="tabindex"@change="handleChange"@keydown.enter="switchValue"/>

aria表示无障碍。

true-valueactiveValuefalse-valueinactiveValue 替换 选中的true 和 未选中的false。

:true-value="activeValue"
:false-value="inactiveValue"

表单输入绑定 | Vue.js (vuejs.org)

因此传入的activeValueinactiveValue属性就为switch开/关的值。

isControlled 是否受控

代码中定义了一个变量isControlled表示是否受控。

const isControlled = ref(props.modelValue !== false)

定义类型时定义的modelValue默认为false,若此时modelValue不为false,说明switch组件是受控的,isControlled 为true,switch组件显示的值为传入值。

监听绑定的modelValue属性,由于监听的是属性,因此要传入一个getter。若modelValue发生变化,也说明此switch组件是受控的。

watch(() => props.modelValue,() => {isControlled.value = true}
)

actualValue 实际值

代码定义了一个变量actualValue表示实际值。

若switch是受控组件,则它的实际值为绑定的modelValue,否则为false。
若实际值actualValue与绑定为开的值activeValue相同,说明switch状态为开(checked=true)

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

到这里,actualValue的值可能是modelValue或false,可能出现不是activeValue / inactiveValue的情况(若不受控,则actualValue为false)。下面代码的目的是确保actualValue的值为activeValue / inactiveValue 。向父组件触发事件,入参为inactiveValue

if (![props.activeValue, props.inactiveValue].includes(actualValue.value)) {emit(UPDATE_MODEL_EVENT, props.inactiveValue)emit(CHANGE_EVENT, props.inactiveValue)emit(INPUT_EVENT, props.inactiveValue)
}

这三个事件分别对应:

export const UPDATE_MODEL_EVENT = 'update:modelValue'
export const CHANGE_EVENT = 'change'
export const INPUT_EVENT = 'input'

checked 开关状态

代码定义了一个变量checked表示开关状态。

const checked = computed(() => actualValue.value === props.activeValue)

参与控制前文所说的文字描述的显示与否。监听checked的变化,同步到input控件。

validateEvent即文档中的 validate-event属性,表示是否触发表单验证。如果需要触发的话,就触发。

watch(checked, (val) => {input.value!.checked = valif (props.validateEvent) {formItem?.validate?.('change').catch((err) => debugWarn(err))}
})

禁用状态、加载状态

定义了表单的禁用状态。若switchDisabled.value为true,则切换状态的方法switchValue会直接return。

const switchDisabled = useFormDisabled(computed(() => props.loading))

加载状态直接用条件渲染,不赘述。

阻止切换 beforeChange

设置beforeChange属性,若返回 false 或者返回 Promise 且被 reject,则停止切换。

若设置了beforeChange,则在触发切换switch前要先执行beforeChange。

在props中解构出beforeChange。若没有设置beforeChange,则直接切换。

beforeChange是一个返回Promise<boolean> | boolean>的方法。若它通过类型校验isPromiseOrBool ,则执行此方法。若promise.resolve的值能通过if判断,则执行切换:handleChange

const switchValue = () => {if (switchDisabled.value) returnconst { beforeChange } = propsif (!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`')}if (isPromise(shouldChange)) {shouldChange.then((result) => {if (result) {handleChange()}}).catch((e) => {debugWarn(COMPONENT_NAME, `some error occurred: ${e}`)})} else if (shouldChange) {handleChange()}
}
  beforeChange: {type: definePropType<() => Promise<boolean> | boolean>(Function),},

文档的例子非常清晰:

<template><el-switchv-model="value1":loading="loading1":before-change="beforeChange1"/><el-switchv-model="value2"class="ml-2":loading="loading2":before-change="beforeChange2"/>
</template>
<script lang="ts" setup>
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)const beforeChange1 = () => {loading1.value = truereturn new Promise((resolve) => {setTimeout(() => {loading1.value = falseElMessage.success('Switch success')return resolve(true)}, 1000)})
}const beforeChange2 = () => {loading2.value = truereturn new Promise((_, reject) => {setTimeout(() => {loading2.value = falseElMessage.error('Switch failed')return reject(new Error('Error'))}, 1000)})
}
</script>

切换 handleChange

val 是inactiveValue / activeValue 。在下一个 DOM 更新周期更新 input.value.checked 的值

const handleChange = () => {const val = checked.value ? props.inactiveValue : props.activeValue// 向外暴露一个input事件,参数为valemit(UPDATE_MODEL_EVENT, val)emit(CHANGE_EVENT, val)emit(INPUT_EVENT, val)//   在下一个 DOM 更新周期更新 input.value.checked 的值nextTick(() => {input.value!.checked = checked.value})
}

emit(CHANGE_EVENT, val)即文档中对外暴露的change事件。

其他内容,如switchKls这种使用ns 生成动态的类名等,在之前的系列里提到过,不再赘述。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com