源碼以下:javascript
<template> <div class="el-switch" :class="{ 'is-disabled': switchDisabled, 'is-checked': checked }" role="switch" :aria-checked="checked" :aria-disabled="switchDisabled" @click="switchValue" > <input class="el-switch__input" type="checkbox" @change="handleChange" ref="input" :id="id" :name="name" :true-value="activeValue" :false-value="inactiveValue" :disabled="switchDisabled" @keydown.enter="switchValue" > <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> </div> </template> <script> import Focus from 'element-ui/src/mixins/focus'; import Migrating from 'element-ui/src/mixins/migrating'; export default { name: 'ElSwitch', mixins: [Focus('input'), Migrating], // 注入elForm對象,防止不和el-form使用時對象不存在的問題。 inject: { elForm: { default: '' } }, props: { value: { type: [Boolean, String, Number], default: false }, disabled: { //是否禁用 type: Boolean, default: false }, width: { //switch 的寬度(像素) type: Number, default: 40 }, activeIconClass: { //switch 打開時所顯示圖標的類名,設置此項會忽略 active-text type: String, default: '' }, inactiveIconClass: { //switch 關閉時所顯示圖標的類名,設置此項會忽略 inactive-text type: String, default: '' }, activeText: String, //switch 打開時的文字描述 inactiveText: String, //switch 關閉時的文字描述 activeColor: { //switch 打開時的背景色 type: String, default: '' }, inactiveColor: { //switch 關閉時的背景色 type: String, default: '' }, activeValue: { //switch 打開時的值 type: [Boolean, String, Number], default: true }, inactiveValue: { //switch 關閉時的值 type: [Boolean, String, Number], default: false }, name: { //switch 對應的 name 屬性 type: String, default: '' }, id: String }, data() { return { coreWidth: this.width }; }, created() { if (!~[this.activeValue, this.inactiveValue].indexOf(this.value)) { this.$emit('input', this.inactiveValue); } }, computed: { //當前的開關組件的狀態 checked() { //父組件中v-model綁定的值是否等於switch 打開時的值 return this.value === this.activeValue; }, //當前組件是否被禁用 switchDisabled() { return this.disabled || (this.elForm || {}).disabled; } }, watch: { checked() { this.$refs.input.checked = this.checked; //在用戶設置了active-color和inactive-color時,經過setBackgroundColor設置開關的背景色 if (this.activeColor || this.inactiveColor) { this.setBackgroundColor(); } } }, methods: { handleChange(event) { //!this.checked爲true,則表示當前是this.value === this.inactiveValue,即爲關着的狀態;須要切換爲開着的狀態,返回this.activeValue this.$emit('input', !this.checked ? this.activeValue : this.inactiveValue); this.$emit('change', !this.checked ? this.activeValue : this.inactiveValue); this.$nextTick(() => { //修改value值並非當即生效,並且爲了防止父組件未修改值,這裏進行了重複賦值 this.$refs.input.checked = this.checked; }); }, //在用戶設置了active-color和inactive-color時,點擊切換開關時,根據this.checked的值設置開關的背景顏色 setBackgroundColor() { //若是 this.checked爲true,即當前switch是打開,開關返回打開時設置的背景色 let newColor = this.checked ? this.activeColor : this.inactiveColor; this.$refs.core.style.borderColor = newColor; this.$refs.core.style.backgroundColor = newColor; }, switchValue() { //在不由用的狀態下才能點擊 !this.switchDisabled && this.handleChange(); }, getMigratingConfig() { return { props: { 'on-color': 'on-color is renamed to active-color.', 'off-color': 'off-color is renamed to inactive-color.', 'on-text': 'on-text is renamed to active-text.', 'off-text': 'off-text is renamed to inactive-text.', 'on-value': 'on-value is renamed to active-value.', 'off-value': 'off-value is renamed to inactive-value.', 'on-icon-class': 'on-icon-class is renamed to active-icon-class.', 'off-icon-class': 'off-icon-class is renamed to inactive-icon-class.' } }; } }, mounted() { /* istanbul ignore if */ this.coreWidth = this.width || 40; if (this.activeColor || this.inactiveColor) { this.setBackgroundColor(); } this.$refs.input.checked = this.checked; } }; </script>
解析:
(1)組件的html結構css
<div class="el-switch"> <input class="el-switch__input" type="checkbox"> <!--顯示左邊的標籤--> <span class="el-switch__label el-switch__label--left"> <i></i> <span></span> </span> <!--中間的開關--> <span class="el-switch__core"></span> <!--顯示右邊的標籤--> <span class="el-switch__label el-switch__label--right"> <i></i> <span></span> </span> </div>
input標籤被隱藏掉了,css部分代碼以下:html
.el-switch__input { position: absolute; width: 0; height: 0; opacity: 0; margin: 0; }
若是把上面的樣式代碼註釋掉,如圖所示:
經過 <input type="checkbox">
的checked屬性來控制文字顯示以及開關的狀態切換。最外層包裹的div是爲了可以經過點擊文字也能切換開關狀態。java
(2)混入的 mixins: [Focus('input'), Migrating]element-ui
主要是migrating.js,該文件主要是用於開發環境下提示一些遷移或者即將修改的屬性和方法的。
示例:我用的element-ui v2.4.9,我按下面這樣寫,off-text屬性在我當前的版本中已經被改成inactive-textpost
<el-switch v-model="value2" off-text="關着"></el-switch>
當我運行以後在控制檯輸出:學習
全部遷移的屬性在組件的getMigratingConfig()方法中:ui
getMigratingConfig() { return { props: { 'on-color': 'on-color is renamed to active-color.', 'off-color': 'off-color is renamed to inactive-color.', 'on-text': 'on-text is renamed to active-text.', 'off-text': 'off-text is renamed to inactive-text.', 'on-value': 'on-value is renamed to active-value.', 'off-value': 'off-value is renamed to inactive-value.', 'on-icon-class': 'on-icon-class is renamed to active-icon-class.', 'off-icon-class': 'off-icon-class is renamed to inactive-icon-class.' } }; }
(3)created方法this
created() { //若是用戶傳入的v-model的值既不是activeValue也不是inactiveValue時,將inactiveValue傳遞出去,開關處於關狀態 if (!~[this.activeValue, this.inactiveValue].indexOf(this.value)) { this.$emit('input', this.inactiveValue); } },
~表明按位非運算符,若是[this.activeValue, this.inactiveValue].indexOf(this.value)爲-1,則按位非後變爲0。spa
參考博文:http://www.javashuo.com/article/p-asirbikn-en.html
http://www.zhuyuntao.cn/2018/10/24/element-ui-focus-js和migrating.js文件源碼學習