vant vue v-model双向绑定checkbox遇到的坑

vant vue v-model双向绑定checkbox遇到的坑

530发表于2020-08-20

今天遇到一个vue诡异的数据绑定问题,下面我给大家分享一下我解决问题思路和方式,以及为什么要这样。

一、问题现象

使用vant的checkbox组件时无法使用v-model来双向绑定选中状态!但是重新打开checbox所在的pop弹窗,又能显示之前操作的最新的选中值,如果不关闭之后重新打开,始终都不更新,感觉好像没有没有反应一样。

二、问题代码

html代码:

<div v-for="item in siteList" :key="'site-'+ item.id" class="list-site-item" @click="toggleSiteItem(item)">
	<div class="site-name">{{ item.siteName }}{{item.siteCode}}</div>
	<div class="site-other-info">
	  <div class="site-check-cont">
		<van-checkbox :name="item.id" v-model="item.isChecked" shape="square">
		</van-checkbox>
	  </div>
	  <div class="site-other-right">
		<div class="site-info-item">
		  <div class="site-info-label">区域:</div>
		  <div>{{ item.areaName }}</div>
		</div>
		<div class="site-info-item">
		  <div class="site-info-label">省份:</div>
		  <div>{{ item.province }}</div>
		</div>
		<div class="site-info-item">
		  <div class="site-info-label">二级单位:</div>
		  <div>{{ item.companyName }}</div>
		</div>
	  </div>
	</div>
	<van-divider />
</div>

为了保持接口的kiss,后台接口不返回是否选中“isChecked”这个字段(为了让接口简单,一般接口都不返回后台没有存储的属性)。

原来的js代码:

searchActiveSites({
	keywords: that.searchSiteKeywords
  }).then(res => {
	that.siteList = res.data;
	
	that.siteList.forEach(m => {
		m.isChecked = false;
	});
	that.loadSitefinished = true;
});
动态的加上属性“isChecked”。

切换选中状态:

let that = this;
// that.$refs.checkboxes[index].toggle();
// debugger;
that.siteList.forEach(m => {
if (m.id === item.id) {
  m.isChecked = !m.isChecked;
}
});

三、解决问题

searchActiveSites({
	keywords: that.searchSiteKeywords
  }).then(res => {
	that.siteList = res.data;
	if (res && res.data.length > 0) {
	  // Vue.set 等同 this.$set
	  that.siteList.forEach(m => {
		that.$set(m, 'isChecked', false);
	  });
	}
	// 诡异问题,不能v-model双向绑定,需要重新打开pop
	// that.siteList.forEach(m => {
	//   m.isChecked = false;
	// });
	that.loadSitefinished = true;
});
使用$set方法添加对象属性!问题就解决了!

四、问题分析及总结

原来vue官方文档有相关说明:

https://cn.vuejs.org/v2/guide/reactivity.html

from clipboard

from clipboard

之前直接赋值添加属性是非响应式的,是动态为根级别的data字段添加property。vue不认为是正常的property属性,也就是没有生成对应setter(你可以console.log看看新加的属性和其他区别),当更改值时也就不能即时通知watcher,正确渲染组件!

我们知道了以上原理之后,使用下面方式也是ok的(亲测有效)


res.data.forEach(m => {
  m.isChecked = false;
});
that.siteList = res.data;
先添加属性,再赋值给data中的属性siteList。反之就不行!!!



小编蓝狐