发现这个问题是因为自己在写学委小程序/高校班级助手的时候,使用的是mpvue框架,使用vue的语法来写小程序的,当遇到了上传图片或者上传文件的时候,由于$data中的数据结构形式使用的跟以往的不太一样,代码片段如下:
data() {
return {
bgIsTransparent: false,
dateTimeArray: [],
dateTime: [],
showCalendar: false,
value: [],
// homeworkPhoto: [], // 图片上传 ps:以前的写法
store: {
course: '',
title: '',
content: '',
deadline: '',
homeworkPhoto: [], // 图片上传 ps:现在的写法
files: [] // 文件上传
}
};
},
正如以上的代码所示,按照以前的写法,我基本上都是将要使用到的数据字段直接放在 $data下面,很少像现在这样子放在 $data中的一个字段来进行统一维护的。因此改成现在这样子的写法之后,虽然在管理数据的时候似乎是方便了很多,但是由于vue特别是mpvue对数据响应式的处理似乎有点问题,mpvue框架本身bug的问题吧应该是,就会造成如标题所描述的问题,就是数组和对象更改后视图不刷新的问题。
一般来说,按照vue官方文档所说,如果想要动态的给一个对象添加一个属性,需要使用vue.set或者vm. $set来添加响应式的属性,只有这样子写才会给属性添加上getter和setter,这样子才能做到在响应式系统内触发状态更新。但是呢这次的情况跟以往的不一样,以往的是给对象动态添加属性,但是这次的是给对象中的属性(这里是一个数组)动态的添加元素,我尝试过使用vue.set或者vm. $set来解决问题,会这样想是因为数组本质上其实也是一个对象,数组的下标也就是index索引其实也就是对象的键值对中的键,这样子理解的话就会理所当然地想到了使用vue.set或者vm. $set,然而并不起作用。
查看了vue官方文档以及参考了他人的博文,似乎找到了解决办法。
按照官方的说法,通过赋值改变改变整个属性,就可以触发setter,从而使数据也能在视图层同步刷新。
为什么会出现这样子的情况呢,是因为vue底层实现数据的双向绑定是通过用Object.defineProety来给每个属性添加getter和setter来实现的,因此会有以上的问题。
然而,值得注意的是,尽管vue对以上的这些方法,特别是push(),splice()这两个常用的方法进行了改造,但是通过验证,在mpvue中并不会触发setter从而使视图层同步刷新,但是在vue中却是没问题,这估计是mpvue本身的坑,开发过程中有时候也会发现$set好像也不是挺管用。。。不知道为什么,反正就是这样,如果有解决办法的朋友们请在留言区友好地给个留言吧谢谢!
因此稳重起见,例如在以上的那个store.homeworkPhoto中,我们给整个数组属性改掉是可以触发setter从而使视图层同步刷新的,并且得益于vue框架本身的原因,我们可以放心地直接将整个store.homeworkPhoto重新赋值。
你可能认为这将导致 Vue 丢弃现有 DOM 并重新渲染整个列表。幸运的是,事实并非如此。Vue 为了使得 DOM 元素得到最大范围的重用而实现了一些智能的启发式方法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。
除了直接赋值,我们也可以新建一个数组或者新建一个对象等的方法,然后通过concat()拼接,从而直接触发setter来使dom视图层能同步刷新
let tempArray = [];
tempArray.push(`https://${data.Location}`);
self.store.homeworkPhoto = self.store.homeworkPhoto.concat(tempArray);
let homeworkPhoto = this.store.homeworkPhoto.concat();
homeworkPhoto.splice(index, 1);
this.store.homeworkPhoto = homeworkPhoto;
let tempArray = [];
tempArray.push(obj);
self.store.files = self.store.files.concat(tempArray);
let tempStoreFiles = self.store.files.concat();
tempStoreFiles[filesBeginLength + index].progress = progressData.percent * 100;
self.store.files = tempStoreFiles;
let tempStoreFiles = self.store.files.concat();
tempStoreFiles[filesBeginLength + index].fileUrl = `https://${data.Location}`;
self.store.files = tempStoreFiles;
vue官方文档-数组更新检测
解析Vue数据/数组对象改变视图不更新
Vue中数组和对象更改后视图不刷新的问题