开关(Switch)选择组件是一种用户界面元素,允许用户在两种状态(通常是开/关、是/否、启用/禁用等)之间进行切换。这种组件在移动应用、桌面软件、网页以及物联网设备中广泛应用。以下是对开关Switch选择组件的详细介绍:
一、基本概念
开关Switch选择组件通常由一个滑块和一个滑道组成。滑块是用户可以拖动的部分,而滑道是背景。用户可以通过拖动滑块或点按开关来改变其状态。
二、主要属性
- 状态:
- 表示开关的当前状态,通常是一个布尔值(true/false或1/0)。
- 状态改变回调:
- 当开关状态发生变化时调用的回调函数。
- 该函数通常接收一个新的状态值作为参数。
- 启用/禁用:
- 控制开关是否可用。
- 当设置为禁用状态时,用户无法更改开关的状态。
- 文本标签:
- 在某些实现中,可以为开关的打开和关闭状态设置文本标签。
- 这些标签通常用于提供更清晰的指示或说明。
- 颜色(colors):
- 自定义开关的颜色,包括滑块和滑道的颜色。
- 某些框架允许为开关的不同状态(打开/关闭)设置不同的颜色。
三、组件扩展
基于uview类型的u-switch我们增加了有效文本、无效文本及颜色。扩展组件如下。
<template><viewclass="u-switch":class="[valueCom? 'u-switch--on' : '', disabled ? 'u-switch--disabled' : '']"@tap="onClick":style="[switchStyle]"><viewclass="u-switch__node node-class":style="nodeStyle"><u-loading:show="loading"class="u-switch__loading":size="size * 0.6":color="loadingColor"/></view><view v-if="activeText || inactiveText" class="u-switch__text" :class="{'u-switch__text-end':!valueCom}" ><text v-if="!valueCom" class="u-switch__text--inactive" :style="{color:inactiveTextColor}">{{ inactiveText }}</text><text v-else class="u-switch__text--active" :style="{color:activeTextColor}">{{ activeText }}</text></view></view>
</template><script>
/*** switch 开关选择器* @description 选择开关一般用于只有两个选择,且只能选其一的场景。* @tutorial https://www.uviewui.com/components/switch.html* @property {Boolean} loading 是否处于加载中(默认false)* @property {Boolean} disabled 是否禁用(默认false)* @property {String Number} size 开关尺寸,单位rpx(默认50)* @property {String} active-color 打开时的背景色(默认#19be6b)* @property {Boolean} inactive-color 关闭时的背景色(默认#ffffff)* @property {Boolean | Number | String} active-value 打开选择器时通过change事件发出的值(默认true)* @property {Boolean | Number | String} inactive-value 关闭选择器时通过change事件发出的值(默认false)* @event {Function} change 在switch打开或关闭时触发* @example <u-switch v-model="checked" active-color="red" inactive-color="#eee"></u-switch>*/
export default {name: "u-switch",emits: ["update:modelValue", "input", "change"],props: {// 通过v-model双向绑定的值value: {type: [Number, String, Boolean],default: false},modelValue: {type: [Number, String, Boolean],default: false},// 是否为加载中状态loading: {type: Boolean,default: false},// 是否为禁用装填disabled: {type: Boolean,default: false},// 开关尺寸,单位rpxsize: {type: [Number, String],default: 50},// 打开时的背景颜色activeColor: {type: String,default: "#19be6b"},// 关闭时的背景颜色inactiveColor: {type: String,default: "#ffffff"},// 是否使手机发生短促震动,目前只在iOS的微信小程序有效(2020-05-06)vibrateShort: {type: Boolean,default: false},// 打开选择器时的值activeValue: {type: [Number, String, Boolean],default: true},// 关闭选择器时的值inactiveValue: {type: [Number, String, Boolean],default: false},activeText: {type: String,default: ''},activeTextColor: {type: String,default: "#ffffff"},inactiveText: {type: String,default: ''},inactiveTextColor: {type: String,default: "#999999"},},data() {return {switchWidth:this.size,};},computed: {valueCom() {// #ifndef VUE3return this.value;// #endif// #ifdef VUE3return this.modelValue;// #endif},switchStyle() {let style = {};style.fontSize = this.size + "rpx";style.backgroundColor = this.valueCom ? this.activeColor : this.inactiveColor;style.width = this.$u.addUnit(this.switchWidth*2);return style;},loadingColor() {return this.valueCom ? this.activeColor : null;},nodeStyle(){const style = {};style.width = this.$u.addUnit(this.size);style.height = this.$u.addUnit(this.size);style.transform = `translateX(${this.valueCom ? this.switchWidth - this.size/2 : 0}px)`;return style;}},methods: {onClick() {if (!this.disabled && !this.loading) {// 使手机产生短促震动,微信小程序有效,APP(HX 2.6.8)和H5无效if (this.vibrateShort) uni.vibrateShort();this.$emit("input", this.valueCom==this.activeValue ? this.inactiveValue : this.activeValue);this.$emit("update:modelValue", this.valueCom==this.activeValue ? this.inactiveValue : this.activeValue);// 放到下一个生命周期,因为双向绑定的value修改父组件状态需要时间,且是异步的this.$nextTick(() => {this.$emit("change", this.valueCom==this.activeValue ? this.inactiveValue : this.activeValu);});}},updateSwitchWidth() {let textLength = Math.max(this.activeText.length,this.inactiveText.length)this.switchWidth = Math.max(textLength*12+10+this.size/2, this.size)}},mounted() {this.updateSwitchWidth();},
};
</script><style lang="scss" scoped>
@import "../../libs/css/style.components.scss";.u-switch {position: relative;/* #ifndef APP-NVUE */display: inline-block;/* #endif */box-sizing: initial;width: 2em;height: 1em;background-color: #fff;border: 1px solid rgba(0, 0, 0, 0.1);border-radius: 1em;transition: background-color 0.3s;font-size: 50rpx;&__text {position: absolute;top: 0;left: 0;right: 0;bottom: 0;display: flex;align-items: center;justify-content: space-between;padding: 0 10rpx;font-size: 24rpx;&-end{justify-content: flex-end;}&--inactive {color: #999999;white-space: nowrap;text-align: right;}&--active {color: #fff;white-space: nowrap;}}
}.u-switch__node {@include vue-flex;align-items: center;justify-content: center;position: absolute;top: 0;left: 0;border-radius: 100%;z-index: 1;background-color: #fff;background-color: #fff;box-shadow: 0 3px 1px 0 rgba(0, 0, 0, 0.05), 0 2px 2px 0 rgba(0, 0, 0, 0.1),0 3px 3px 0 rgba(0, 0, 0, 0.05);box-shadow: 0 3px 1px 0 rgba(0, 0, 0, 0.05), 0 2px 2px 0 rgba(0, 0, 0, 0.1),0 3px 3px 0 rgba(0, 0, 0, 0.05);transition: transform 0.3s cubic-bezier(0.3, 1.05, 0.4, 1.05);transition: transform 0.3s cubic-bezier(0.3, 1.05, 0.4, 1.05),-webkit-transform 0.3s cubic-bezier(0.3, 1.05, 0.4, 1.05);transition: transform cubic-bezier(0.3, 1.05, 0.4, 1.05);transition: transform 0.3s cubic-bezier(0.3, 1.05, 0.4, 1.05);
}.u-switch__loading {@include vue-flex;align-items: center;justify-content: center;
}.u-switch--on {background-color: #1989fa;
}.u-switch--on .u-switch__node {transform: translateX(100%);
}.u-switch--disabled {opacity: 0.4;
}
</style>
四、可视化设计
拖动开关组件进设计区。
保存源码至本地查看效果
<template><view class="container container329152"><u-form-item class="diygw-col-24" label="开关" prop="switch"><view class="flex diygw-col-24"><u-switch :size="44" :activeValue="1" :inactiveValue="0" inactiveTextColor="#000000" activeTextColor="#ffffff" v-model="switched" slot="right"></u-switch></view></u-form-item><u-form-item class="diygw-col-24" label="开关" prop="switch1"><view class="flex diygw-col-24"><u-switch :size="44" activeText="有效" inactiveText="无效" :activeValue="1" :inactiveValue="0" inactiveTextColor="#000000" activeTextColor="#ffffff" v-model="switch1" slot="right"></u-switch></view></u-form-item><u-form-item class="diygw-col-24" label="开关" prop="switch2"><view class="flex diygw-col-24"><u-switch :size="44" activeText="男" inactiveText="女" :activeValue="1" :inactiveValue="0" inactiveTextColor="#000000" activeTextColor="#ffffff" v-model="switch2" slot="right"></u-switch></view></u-form-item><view class="clearfix"></view></view>
</template><script>export default {data() {return {//用户全局信息userInfo: {},//页面传参globalOption: {},//自定义全局变量globalData: {},listNum: 1,list: {code: 200,msg: '获取数据成功',data: [{title: '标题1',remark: '描述1',id: 1,attr: {title: '标题1'},img: 'https://php.diygw.com/logo.png'},{title: '标题2',remark: '描述2',id: 2,attr: {title: '标题2'},img: 'https://php.diygw.com/logo.png'},{title: '标题3',remark: '描述3',id: 3,attr: {title: '标题3'},img: 'https://php.diygw.com/logo.png'},{title: '标题4',remark: '描述4',id: 4,attr: {title: '标题4'},img: 'https://php.diygw.com/logo.png'},{title: '标题5',remark: '描述5',id: 5,attr: {title: '标题5'},img: 'https://php.diygw.com/logo.png'},{title: '标题6',remark: '描述6',id: 6,attr: {title: '标题6'},img: 'https://php.diygw.com/logo.png'},{title: '标题7',remark: '描述7',id: 7,attr: {title: '标题7'},img: 'https://php.diygw.com/logo.png'},{title: '标题8',remark: '描述8',id: 8,attr: {title: '标题8'},img: 'https://php.diygw.com/logo.png'},{title: '标题9',remark: '描述9',id: 9,attr: {title: '标题9'},img: 'https://php.diygw.com/logo.png'},{title: '标题10',remark: '描述10',id: 10,attr: {title: '标题10'},img: 'https://php.diygw.com/logo.png'}]},switched: 1,switch1: 1,switch2: 1};},onPageScroll(e) {const scrollTop = e.scrollTop;this.headerBackgroundStyle = this.headerBackgroundStyle || { background: 'none' };if (scrollTop <= 80) {const opacity = scrollTop / 100;const color = `rgba(255, 255, 255, ${opacity})`;this.headerBackgroundStyle.background = color;} else {this.headerBackgroundStyle.background = '#ffffff';}},onShow() {this.setCurrentPage(this);},onLoad(option) {this.setCurrentPage(this);if (option) {this.setData({globalOption: this.getOption(option)});}this.init();},methods: {async init() {await this.listApi();},// 列表数据 API请求方法async listApi(param) {let thiz = this;param = param || {};//如果请求要重置页面,请配置点击附加参数refresh=1 增加判断如输入框回调param不是对象if (param.refresh || typeof param != 'object') {this.listNum = 1;}//请求地址及请求数据,可以在加载前执行上面增加自己的代码逻辑let http_url = 'https://php.diygw.com/article.php';let http_data = {pageNum: this.listNum,pageSize: 10,sctdown: param.sctdown || this.sctdown};let http_header = {};let list = await this.$http.post(http_url, http_data, http_header, 'json');let datarows = list.rows;if (http_data.pageNum == 1) {this.list = list;} else if (datarows) {let rows = this.list.rows.concat(datarows);list.rows = rows;this.list = list;}if (datarows && datarows.length > 0) {this.listNum = this.listNum + 1;}this.globalData.isshow = true;console.log(http_data.sctdown);}},onPullDownRefresh() {// 列表数据 API请求方法this.listNum = 1;this.listApi();uni.stopPullDownRefresh();},onReachBottom() {// 列表数据 API请求方法this.listApi();}};
</script><style lang="scss" scoped>.container329152 {}
</style>