The source code is as follows:
<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], // Inject the El form object to prevent the problem that the object does not exist when it is not used with El form. inject: { elForm: { default: '' } }, props: { value: { type: [Boolean, String, Number], default: false }, disabled: { //Is it forbidden? type: Boolean, default: false }, width: { //Width of switch (pixels) type: Number, default: 40 }, activeIconClass: { //The class name of the icon displayed when switch is turned on. Setting this option will ignore active text type: String, default: '' }, inactiveIconClass: { //Class name of the icon displayed when switch is turned off. Setting this option will ignore inactive text type: String, default: '' }, activeText: String, //Text description when switch is turned on inactiveText: String, //Text description when switch is turned off activeColor: { //Background color when switch is on type: String, default: '' }, inactiveColor: { //Background color when switch is off type: String, default: '' }, activeValue: { //Value when switch is on type: [Boolean, String, Number], default: true }, inactiveValue: { //switch off value type: [Boolean, String, Number], default: false }, name: { //name attribute corresponding to switch 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: { //Current switch component status checked() { //Whether the value of the v-model binding in the parent component is equal to the value when switch is opened return this.value === this.activeValue; }, //Is the current component disabled switchDisabled() { return this.disabled || (this.elForm || {}).disabled; } }, watch: { checked() { this.$refs.input.checked = this.checked; //When the user has set active color and inactive color, set the background color of the switch through setBackgroundColor if (this.activeColor || this.inactiveColor) { this.setBackgroundColor(); } } }, methods: { handleChange(event) { //! if this.checked is true, it means that this.value === this.inactiveValue is currently closed; if you need to switch to the open state, you need to return this.activeValue this.$emit('input', !this.checked ? this.activeValue : this.inactiveValue); this.$emit('change', !this.checked ? this.activeValue : this.inactiveValue); this.$nextTick(() => { //Modifying the value value does not take effect immediately, and in order to prevent the parent component from not modifying the value, repeated assignments are made here this.$refs.input.checked = this.checked; }); }, //When the user has set active color and inactive color, when clicking the toggle switch, set the background color of the switch according to the value of this.checked setBackgroundColor() { //If this.checked is true, that is, the current switch is on, and the switch returns the background color set when it is turned on let newColor = this.checked ? this.activeColor : this.inactiveColor; this.$refs.core.style.borderColor = newColor; this.$refs.core.style.backgroundColor = newColor; }, switchValue() { //Click only when it is not disabled !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>
Analysis:
(1) html structure of components
<div class="el-switch"> <input class="el-switch__input" type="checkbox"> <!--Show left label--> <span class="el-switch__label el-switch__label--left"> <i></i> <span></span> </span> <!--Middle switch--> <span class="el-switch__core"></span> <!--Show label on right--> <span class="el-switch__label el-switch__label--right"> <i></i> <span></span> </span> </div>
The input tag is hidden. The code of css is as follows:
.el-switch__input { position: absolute; width: 0; height: 0; opacity: 0; margin: 0; }
If the above style code is commented out, as shown in the figure:
The text display and switch status are controlled by the checked attribute of < input type = "checkbox" >. The outer layer of the div is to be able to switch the status by clicking the text.
(2) mixins in: [focus ('input '), migrating]
It is mainly migration.js, which is mainly used to prompt some properties and methods to be migrated or modified in the development environment.
Example: the element UI v2.4.9 I use, I write as follows: the off text attribute has been changed to inactive text in my current version
< El switch V-model = "Value2" off text = "off" >
All migrated properties are in the getMigratingConfig() method of the component:
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 method
created() { //If the value of the v-model passed in by the user is neither active value nor inactive value, the inactive value is passed out and the switch is off if (!~[this.activeValue, this.inactiveValue].indexOf(this.value)) { this.$emit('input', this.inactiveValue); } },
~Represents the bitwise non operator. If [this.activevalue, this.inactive value]. Indexof (this. Value) is - 1, then the bitwise non becomes 0.
Reference blog: https://juejin.im/post/5b861db0e51d4538aa1b5630
http://www.zhuyuntao.cn/2018/10/24/element-ui-focus-js and migration.js file source code learning