Home > Article > Web Front-end > How to solve the problem that Vue cannot detect changes in arrays or objects?
Below I will share with you an article that solves the problem that Vue cannot detect changes in arrays or objects. It has a good reference value and I hope it will be helpful to everyone.
Let’s look at an example:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue</title> <script src="https://unpkg.com/vue@2.3.3/dist/vue.js"></script> <style> li:hover { cursor: pointer; } </style> </head> <body> <p class="wrap"> <ul> <li v-for="item,index in items" v-on:click="handle(index)"> <span>{{item.name}}</span> <span>{{numbers[index]}}</span> </li> </ul> </p> <script> var vm = new Vue({ el: ".wrap", data: { numbers: [], items: [ {name: 'jjj'}, {name: 'kkk'}, {name: 'lll'}, ] }, methods: { handle: function (index) { // WHY: 更新数据,view层未渲染,但通过console这个数组可以发现数据确实更新了 if (typeof(this.numbers[index]) === "undefined" ) { // 注:下面这么设置是可以的。例如 // var arr = []; // arr[3]=3; // console.log(arr) //[empty × 3, 3] this.numbers[index] = 1; // this.numbers.splice(index,0,1) //用splice方法能同步显示,但得不到想要的效果 } else { this.numbers[index]++; // this.numbers.splice(index,1,this.numbers[index]++) } // console.log(this.numbers) } } }); </script> </body> </html>
The effect you want to achieve is to click li to see if vm.nymbers[index] exists, and there is no setting. is 1, plus 1 if present.
After clicking, the number was not updated in the view layer. However, it was found through console printing that the data was updated, but the view layer did not detect it in time.
Look at another change:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue</title> <script src="https://unpkg.com/vue@2.3.3/dist/vue.js"></script> <style> li:hover { cursor: pointer; } </style> </head> <body> <p class="wrap"> <ul> <li v-for="item,index in items" v-on:click="handle(index)"> <span>{{item.name}}</span> <!--<span>{{numbers[index]}}</span>--> </li> </ul> </p> <script> var vm = new Vue({ el: ".wrap", data: { // numbers: [], items: [ {name: 'jjj'}, {name: 'kkk'}, {name: 'lll'}, ] }, methods: { handle: function (index) { // 不是数组,这里更新数据就可以直接在view层渲染 this.items[index].name += " success"; // console.log(this.numbers) } } }); </script> </body> </html>
You can see that the view layer here can be updated in time, but why can't it be done when it comes to the array?
Let’s take a look at the official documentation of Vue2.0:
Due to JavaScript limitations, Vue cannot detect the following changed arrays:
When you use the index to directly set an item, for example: vm.items[indexOfItem] = newValue
When you modify the length of the array, for example: vm.items.length = newLength
In order to solve the first type of problem, the following two methods can achieve the same effect as vm.items[indexOfItem] = newValue, and will also trigger status updates:
// Vue.set Vue.set(example1.items, indexOfItem, newValue)
// Array.prototype.splice example1.items.splice(indexOfItem, 1, newValue)
You can also use vm.$ set instance method, which is just an alias for the global Vue.set.
Or due to JavaScript limitations, Vue cannot detect the addition or deletion of object properties:
var vm = new Vue({ data: { a: 1 } }) // `vm.a` 现在是响应式的 vm.b = 2 // `vm.b` 不是响应式的
For already created instances, Vue cannot dynamically add root-level responsive properties. However, you can add reactive properties to nested objects using the Vue.set(object, key, value) method. For example, for:
var vm = new Vue({ data: { userProfile: { name: 'Anika' } } })
Sometimes you may need to assign multiple new properties to an existing object, such as using Object.assign() or _.extend(). In this case, you should create a new object with the properties of both objects. So, if you want to add a new reactive attribute, instead of doing it like this:
Object.assign(this.userProfile, { age: 27, favoriteColor: 'Vue Green' })
you should do this:
this.userProfile = Object.assign({}, this.userProfile, { age: 27, favoriteColor: 'Vue Green' })
Therefore, the above example should be changed to :
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue</title> <script src="https://unpkg.com/vue@2.3.3/dist/vue.js"></script> <style> li:hover { cursor: pointer; } </style> </head> <body> <p class="wrap"> <ul> <li v-for="item,index in items" v-on:click="handle(index)"> <span>{{item.name}}</span> <span>{{numbers[index]}}</span> </li> </ul> </p> <script> var vm = new Vue({ el: ".wrap", data: { numbers: [], items: [ {name: 'jjj'}, {name: 'kkk'}, {name: 'lll'}, ] }, methods: { handle: function (index) { if (typeof(this.numbers[index]) === "undefined" ) { this.$set(this.numbers, index, 1); //(arr,index,newvalue) } else { this.$set(this.numbers, index, ++this.numbers[index]); } } } }); </script> </body> </html>
Done!
1.17 Supplement----------------------------------
How to understand "Vue cannot dynamically add root-level responsive properties to already created instances"?
For example:
var vm=new Vue({ el:'#test', data:{ //data中已经存在info根属性 info:{ name:'小明' } } }); //给info添加一个性别属性 Vue.set(vm.info,'sex','男');
The above is the correct approach, but if you do the following, an error will be reported:
Vue.set(vm.data,'sex','男')
Actually , you cannot directly add attributes to data, but you can add attributes to objects in data.
Actually vm.data is undefined.
The above is what I compiled for everyone. I hope it will be helpful to everyone in the future.
Related articles:
NodeJS parent process and child process resource sharing principles and implementation methods
Vue implements active click switching method
The above is the detailed content of How to solve the problem that Vue cannot detect changes in arrays or objects?. For more information, please follow other related articles on the PHP Chinese website!