164 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Vue
		
	
	
	
		
		
			
		
	
	
			164 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Vue
		
	
	
	
|  | <template> | |||
|  | 	<view class="u-switch" :class="[value == true ? 'u-switch--on' : '', disabled ? 'u-switch--disabled' : '']" @tap="onClick" | |||
|  | 	 :style="[switchStyle]"> | |||
|  | 		<view class="u-switch__node node-class" :style="{ | |||
|  | 			width: $u.addUnit(this.size), | |||
|  | 			height: $u.addUnit(this.size) | |||
|  | 		}"> | |||
|  | 			<u-loading :show="loading" class="u-switch__loading" :size="size * 0.6" :color="loadingColor" /> | |||
|  | 		</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 打开时的背景色(默认#2979ff) | |||
|  | 	 * @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", | |||
|  | 		props: { | |||
|  | 			// 是否为加载中状态
 | |||
|  | 			loading: { | |||
|  | 				type: Boolean, | |||
|  | 				default: false | |||
|  | 			}, | |||
|  | 			// 是否为禁用装填
 | |||
|  | 			disabled: { | |||
|  | 				type: Boolean, | |||
|  | 				default: false | |||
|  | 			}, | |||
|  | 			// 开关尺寸,单位rpx
 | |||
|  | 			size: { | |||
|  | 				type: [Number, String], | |||
|  | 				default: 50 | |||
|  | 			}, | |||
|  | 			// 打开时的背景颜色
 | |||
|  | 			activeColor: { | |||
|  | 				type: String, | |||
|  | 				default: '#2979ff' | |||
|  | 			}, | |||
|  | 			// 关闭时的背景颜色
 | |||
|  | 			inactiveColor: { | |||
|  | 				type: String, | |||
|  | 				default: '#ffffff' | |||
|  | 			}, | |||
|  | 			// 通过v-model双向绑定的值
 | |||
|  | 			value: { | |||
|  | 				type: Boolean, | |||
|  | 				default: false | |||
|  | 			}, | |||
|  | 			// 是否使手机发生短促震动,目前只在iOS的微信小程序有效(2020-05-06)
 | |||
|  | 			vibrateShort: { | |||
|  | 				type: Boolean, | |||
|  | 				default: false | |||
|  | 			}, | |||
|  | 			// 打开选择器时的值
 | |||
|  | 			activeValue: { | |||
|  | 				type: [Number, String, Boolean], | |||
|  | 				default: true | |||
|  | 			}, | |||
|  | 			// 关闭选择器时的值
 | |||
|  | 			inactiveValue: { | |||
|  | 				type: [Number, String, Boolean], | |||
|  | 				default: false | |||
|  | 			}, | |||
|  | 		}, | |||
|  | 		data() { | |||
|  | 			return { | |||
|  | 
 | |||
|  | 			} | |||
|  | 		}, | |||
|  | 		computed: { | |||
|  | 			switchStyle() { | |||
|  | 				let style = {}; | |||
|  | 				style.fontSize = this.size + 'rpx'; | |||
|  | 				style.backgroundColor = this.value ? this.activeColor : this.inactiveColor; | |||
|  | 				return style; | |||
|  | 			}, | |||
|  | 			loadingColor() { | |||
|  | 				return this.value ? this.activeColor : null; | |||
|  | 			} | |||
|  | 		}, | |||
|  | 		methods: { | |||
|  | 			onClick() { | |||
|  | 				if (!this.disabled && !this.loading) { | |||
|  | 					// 使手机产生短促震动,微信小程序有效,APP(HX 2.6.8)和H5无效
 | |||
|  | 					if(this.vibrateShort) uni.vibrateShort(); | |||
|  | 					this.$emit('input', !this.value); | |||
|  | 					// 放到下一个生命周期,因为双向绑定的value修改父组件状态需要时间,且是异步的
 | |||
|  | 					this.$nextTick(() => { | |||
|  | 						this.$emit('change', this.value ? this.activeValue : this.inactiveValue); | |||
|  | 					}) | |||
|  | 				} | |||
|  | 			} | |||
|  | 		} | |||
|  | 	}; | |||
|  | </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; | |||
|  | 	} | |||
|  | 
 | |||
|  | 	.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> |