前言
近期产品需求:Vue2移动端项目需要在
switch
开关内显示文字,看Vantui
没有对应功能,因此自己手撸写了这个组件。
一、最终效果
二、参数配置
1、代码示例:
<t-switch v-model="check"/>
2、配置参数(t-switch Attributes)
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
v-model | 绑定值 | boolean / string / number | — |
disabled | 是否禁用 | boolean | false |
width | switch 的宽度(像素) | number | 55 |
active-icon-class | switch 打开时所显示图标的类名,设置此项会忽略 active-text | string | — |
inactive-icon-class | switch 关闭时所显示图标的类名,设置此项会忽略 inactive-text | string | — |
active-text | switch 打开时的文字描述 | string | — |
inactive-text | switch 关闭时的文字描述 | string | — |
active-value | switch 打开时的值 | boolean / string / number | true |
inactive-value | switch 关闭时的值 | boolean / string / number | false |
active-color | switch 打开时的背景色 | string | #2b73bb |
inactive-color | switch 关闭时的背景色 | string | #ccc |
name | switch 对应的 name 属性 | string | — |
3、events 事件
事件名称 | 说明 | 回调参数 |
---|---|---|
change | switch 状态发生变化时的回调函数 | 新状态的值 |
三、源码
<template><divclass="t-switch":class="{ 'is-disabled': switchDisabled, 'is-checked': checked }"role="switch":aria-checked="checked":aria-disabled="switchDisabled"@click.prevent="switchValue"><inputclass="t-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="['t-switch__label', 't-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="t-switch__core" ref="core" :style="{ 'width': coreWidth + 'px' }"></span><span:class="['t-switch__label', 't-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>export default {name: 'TSwitch',props: {value: {type: [Boolean, String, Number],default: false},disabled: {type: Boolean,default: false},width: {type: Number,default: 55},activeIconClass: {type: String,default: ''},inactiveIconClass: {type: String,default: ''},activeText: String,inactiveText: String,activeColor: {type: String,default: '#2b73bb'},inactiveColor: {type: String,default: '#ccc'},activeValue: {type: [Boolean, String, Number],default: true},inactiveValue: {type: [Boolean, String, Number],default: false},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() {return this.value === this.activeValue;},switchDisabled() {return this.disabled}},watch: {checked() {this.$refs.input.checked = this.checked;if (this.activeColor || this.inactiveColor) {this.setBackgroundColor();}}},methods: {handleChange(event) {const val = this.checked ? this.inactiveValue : this.activeValue;this.$emit('input', val);this.$emit('change', val);this.$nextTick(() => {if (this.$refs.input) {this.$refs.input.checked = this.checked;}});},setBackgroundColor() {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();}},mounted() {/* istanbul ignore if */this.coreWidth = this.width || 40;if (this.activeColor || this.inactiveColor) {this.setBackgroundColor();}this.$refs.input.checked = this.checked;this.$refs['input'].focus()}
};
</script>
<style lang="scss" scoped>
.t-switch {display: -webkit-inline-box;display: -ms-inline-flexbox;display: inline-flex;-webkit-box-align: center;-ms-flex-align: center;align-items: center;position: relative;font-size: 14px;height: 22px;vertical-align: middle;&.is-disabled {opacity: 0.6;.t-switch__core,.t-switch__label {cursor: not-allowed;}}&.is-checked {.t-switch__core {&::after {left: 100%;margin-left: -19px;}}}.label-fade-enter,.label-fade-leave-active {opacity: 0;}.t-switch__label {margin: 0;position: absolute;display: none;color: #fff;&.is-active {display: inline-block;color: #fff;}* {line-height: 1;font-size: 14px;display: inline-block;}}.t-switch__label--left {right: 5px;z-index: 9;}.t-switch__label--right {left: 5px;z-index: 9;}.t-switch__input {position: absolute;width: 0;height: 0;opacity: 0;margin: 0;}.t-switch__core {margin: 0;position: relative;width: 40px;height: 22px;border: 1px solid #dcdfe6;outline: 0;border-radius: 10px;-webkit-box-sizing: border-box;box-sizing: border-box;background: #dcdfe6;-webkit-transition: border-color 0.3s, background-color 0.3s;transition: border-color 0.3s, background-color 0.3s;&:after {content: "";position: absolute;top: 1px;left: 1px;border-radius: 100%;-webkit-transition: all 0.3s;transition: all 0.3s;width: 18px;height: 18px;background-color: #fff;}}
}
</style>
相关文章
基于ElementUi再次封装基础组件文档
基于ant-design-vue再次封装基础组件文档
vue3+ts基于Element-plus再次封装基础组件文档