1、前言

因近期项目原因,uniapp官方提供的switch组件并不能满足项目的需求。因此写了一个可自定义改变开关大小、颜色背景等功能的开关。

  • 该组件中使用到的动画方法来自于uniapp官方:动画方法。
  • 另外该组件还使用了vue3、ts。

2、组件及使用

2.1、组件代码如下:

<template>
	<view class="switch-container" :style="[{ background: (isSwitch?bj_color:un_bj_color), width: (pWidth+ 'rpx'), height: (pHeight + 'rpx'), 'border-radius': (pWidth+'rpx')}]">
		<view class="switch_view" :style="[{'border-radius': (pWidth+'rpx')}]" @click.prevent.stop="changeSwitch"></view>
		<view class="disabled" v-if="disabled" :style="[{'border-radius': (pWidth+'rpx')}]"></view>
		<view class="position-box" :animation="animationData">
			<view class="position_view" :style="[{ background: (isSwitch?checked_bj_color:un_checked_bj_color), width: (sWidth+ 'rpx'), height: (sHeight + 'rpx'),'border-radius': (pWidth+'rpx')}]"></view>
		</view>
	</view>
</template>


<script lang="ts" setup>
	import {
		ref,
		onBeforeMount,
		watchEffect
	} from 'vue'
	let props = defineProps({
		defaultSwitch: {// 默认状态
			type: Boolean,
			default: false
		},
		isFail: {// 按钮改变状态是否失败
			type: Boolean,
			default: false
		},
		pHeight: {// 开关高
			type: Number,
			default: 50
		},
		pWidth: {//卡关宽
			type: Number,
			default: 100
		},
		sHeight: {//开关小圆高
			type: Number,
			default: 36
		},
		sWidth: {//开关小圆宽
			type: Number,
			default: 36
		},
		disabled: {//是否禁用
			type: Boolean,
			default: false
		},
		bj_color: {//开时背景色
			type: String,
			default: 'linear-gradient(110.47deg, #3295ED 14.95%, #6CF3EB 87.77%), #4F86F5'
		},
		un_bj_color: {//关时背景色
			type: String,
			default: '#FFF'
		},
		checked_bj_color: {//开 小圆背景色
			type: String,
			default: '#fff'
		},
		un_checked_bj_color: {// 关 小圆背景色
			type: String,
			default: '#D9D9D9'
		}
	})
	const emit = defineEmits < {
		(change:String, val:Boolean): void
	} > ()
	// 定义开关状态
	let isSwitch = ref < Boolean > (false)
	// 创建动画
	let initAnimation = uni.createAnimation({
		duration: 500,
		timingFunction: 'ease'
	});
	// 定义动画相关对象
	let animationData = {}
	
	// 动画效果
	const changeAnimation = () => {
		if (!isSwitch.value) {
			animationData = initAnimation.left(0).width('50%').step().export();
		} else {
			animationData = initAnimation.left(props.pWidth / 4).width('50%').step().export();
		}
	}
	
	onBeforeMount(() => {
		isSwitch.value = props.defaultSwitch
	})
	watchEffect(() => {
		if(props.isFail){
			isSwitch.value = props.defaultSwitch
		}
		changeAnimation()
	})
	// change 回调
	const callback = (item) => {
		emit('change', item)
	}
	const changeSwitch = () => {
		if (props.disabled) return
		isSwitch.value = !isSwitch.value
		callback(isSwitch.value)
		changeAnimation()
	}
</script>

<style lang="scss" scoped>
	.switch-container {
		display: flex;
		flex-direction: row;
		border: 1rpx solid #ccc;
		position: relative;

		.switch_view {
			position: absolute;
			top: 0;
			left: 0;
			width: 100%;
			height: 100%;
			z-index: 1;
			display: flex;
		}

		.position-box {
			position: absolute;
			top: 0;
			left: 0;
			bottom: 0;
			right: 0;
			width: 60%;
			height: 100%;
			display: flex;
			justify-content: center;
			align-items: center;

			.position_view {
				border-radius: 50%;

			}

		}

		.disabled {
			position: absolute;
			top: 0;
			left: 0;
			width: 100%;
			height: 100%;
			z-index: 99;
			background: #fff;
			opacity: 0.6;
		}
	}
</style>

2.2、组件使用代码如下

<template>
	<view class="box">
		<mySwitch @change="switchChage"></mySwitch>
		<mySwitch :defaultSwitch="true" class="item1" :pHeight="200" :pWidth="400" :sWidth="50" :sHeight="72" bj_color="red"></mySwitch>
	</view>
</template>

<script lang="ts" setup>
	// 引入组件
	import mySwitch from './compone/index.vue'
	// 组件的change事件
	const switchChage = (val:boolean) =>{
		uni.showToast({
			title:`开关已${val?'开启': '关闭'}`
		})
	}
</script>

3、组件效果展示

在这里插入图片描述

最后,上述代码中,如有不足之处,还望指出。。。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐