uni-app checkbox和switch组件checked属性无效的解决方案

uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、H5、以及各种小程序(微信/支付宝/百度/头条/QQ/钉钉)等多个平台。

相信许多开发者都有遇到过 uni-app 中的 复选框组件(checkbox)和开关组件(switch)在改变 checked 属性会有无效的问题。本篇文章将分析问题的产生和解决方法。

先来一段示例源码

<template>
	<view>
		<view style="padding: 15px;">
			<button size="mini" type="primary" @tap="change(true)">开</button>
			<button size="mini" type="warn" @tap="change(false)">关</button>
		</view>
		<view>
			<switch :checked="flag"></switch>
		</view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				flag:true
			}
		},
		methods: {
			change(flag){
				this.flag = flag;
			}
		}
	}
</script>

<style>

</style>

如上示例代码,开关组件 默认为选中状态,通过点击 开按钮 和 关按钮 来修改 flag 变量是可以正确设置 开关组件的 checked 状态的。

有些时候点击了开关组件切换了状态之后,再通过按钮修改 flag 变量时,开关组件是不会发生状态改变的,也就是出现了文章开篇所说的 checked 属性无效的问题。

那么产生该问题的原因又是什么呢?

经测试发现,当 checked 属性的值发生改变时才会重新更新视图(在vue.js中,通过检测值发生改变后,vue.js会自动修改对应的视图)。这句话有点让人费解。开关组件 的 checked 属性 是可以控制状态(开和关)的。但是点击开关组件本身。该组件是直接切换的组件状态,并没有同步更新 checked 属性 所绑定的值。所以开关组件默认 checked 属性为 true 的时候,点击组件本身会将组件的状态切换为关,但是checked 属性的并没有改变。再通过按钮设置checked 属性的为true时,因checked 属性的值 falg变量还是之前的true。vue.js认为数据并没有发生改变。所以才会出现设置checked 属性无效的问题。

介于上面的说明,对代码做如下修改,问题得到解决:

// html 代码修改如下
<switch :checked="flag" @change="changeSwitch"></switch>

// js 新增 changeSwitch方法 代码如下
changeSwitch(e){
    this.flag = e.detail.value;	//组件点击后获得当前组件状态更新flag变量的值
}

通过增加上面的代码,前述问题得到解决。但是该方法存在许多弊端

  1. 开关组件的状态经常需要 请求异步接口 后再设置状态,上述代码能解决问题,但在页面上会有来回切换的BUG;
  2. 这种方式无法解决 复选框组件(checkbox组件) 的问题,因为复选框组件没有 @change 事件,checkbox-group组件拥有 @change 事件,事件返回的结果是当前 复选框组中已经勾选的值。要从值重新找出点击的是那一个复选框的代码过程明显有点不合理。

为了更好的适应多种需求和方法的通用性,小编给出第二种解决方案。

该问题BUG的产生是 组件的点击事件修改状态后并未同步修改checked 属性造成的,那么放弃组件本身的点击切换功能,由自己的代码逻辑控制 checked 属性 就能从根本上解决该问题。

方案二示例代码:

<template>
	<view>
		<view style="padding: 15px;">
			<button size="mini" type="primary" @tap="change(true)">开</button>
			<button size="mini" type="warn" @tap="change(false)">关</button>
		</view>
		<view class="switch_box">
			<switch :checked="flag"></switch>
			<view class="switch_shade" @tap="changeSwitch"></view>
		</view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				flag:true
			}
		},
		methods: {
			change(flag){
				this.flag = flag;
			},
			changeSwitch(){
				this.flag = !this.flag;
			}
		}
	}
</script>

<style>
.switch_box{
	position: relative;
	display: inline-block;
}
.switch_shade{
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	left: 0;
	z-index: 10;
}
</style>

如上示例代码,做了2件事情:

  1. 设置一个遮罩元素 ".switch_shade" 挡住 开关组件来阻止 开关组件 本身的 点击事件触发。
  2. 将原 开关组件的 @change 事件 改为 遮罩元素的 @tap 事件。

通过点击遮罩,修改 checked 属性 来达到切换组件状态的目的。

若使用 复选框组件 实现 “全选/反选”等功能遇到本篇文章所说的问题时,可以采用方案二的方式解决问题。请各位读者们自行实践。

小编有发布过相同示例的插件,完整源码获取方式:

#1 uni-app 插件市场:异步switch组件 - DCloud 插件市场

#2 gitee 代码仓库:uniapp-extend: uni-app 插件 / 模板分享

更多干货,请持续关注我的博客更新。

作者:黄河爱浪 QQ:1846492969,邮箱:helang.love@qq.com

本文原创,著作权归作者所有,转载请注明原链接及出处。

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值