Vue 改變數組中對象的屬性不重新渲染View的解決方案
在解決問題之前,我們先來了解下 vue響應性原理: Vue最顯著的一個功能是響應系統-- 模型只是一個普通對象,修改對象則會更新視圖。
受到javascript的限制,Vue不能檢測到對象屬性的添加或刪除,因為vue在初始化實列時將屬性轉為getter/setter,所以屬性必須在data對象上才能讓vue轉換它。
但是vue可以使用 Vue.set(object, key, value)方法將響應屬性添加到嵌套的對象上:如下代碼:
Vue.set(obj, '_isHover', true);
或者可以使用vm.$set的實列方法,也是Vue.set方法的別名:
this.$set(obj, '_isHover', false);
問題: 頁面上多個item項, 當我鼠標移動上去的時候,我想在該數組中的對象添加一個屬性 isHover=true, 當鼠標移出的時候,我想讓該屬性變為 isHover=false,然后希望改變對象的屬性的時候讓其重新渲染view層,重新執行rowClasses方法,然后該方法會判斷 isHover是否等於true,如果為true的話,讓其增加一個類名。
代碼如下:
<!DOCTYPE html> <html> <head> <title>演示Vue</title> <style> * {margin: 0; padding: 0;} ul, li {list-style: none;} #app {width: 800px; margin: 20px auto; border:1px solid #ccc; border-bottom: none;} #app li {height: 32px; line-height: 32px; border-bottom: 1px solid #ccc;} #app li.bgColor {background-color: red;} </style> </head> <body> <div id='app'> <ul> <li v-for="(item, index) in items" @mouseenter.stop="handleMouseIn(index)" @mouseleave.stop="handleMouseOut(index)" :class="rowClasses(index)" > <span>{{item.name}}</span> </li> </ul> </div> </body> <script src="https://tugenhua0707.github.io/vue/vue1/vue.js"></script> <script type="text/javascript"> new Vue({ el: '#app', data: { items: [ {name: 'kongzhi'}, {name: 'longen'}, {name: 'tugenhua'} ] }, computed: { }, methods: { rowClasses (index) { return [ { [`bgColor`]: this.$data.items[index] && this.$data.items[index]._isHover } ] }, handleMouseIn(index) { if (this.$data.items[index]._isHover) { return; } console.log(111); // 可以執行到 this.$data.items[index]._isHover = true; }, handleMouseOut(index) { this.$data.items[index]._isHover = false; } } }); </script> </html>
可以看到鼠標移動上去的時候 沒有效果。
解決的方案如下:
1. 使用 Object.assign
鼠標移動上去的時候 代碼可以改成如下:
this.$data.items[index]._isHover = true; this.$data.items = Object.assign({}, this.$data.items);
鼠標移出的時候,代碼改成如下:
this.$data.items[index]._isHover = false; this.$data.items = Object.assign({}, this.$data.items);
代碼如下:
<!DOCTYPE html> <html> <head> <title>演示Vue</title> <style> * {margin: 0; padding: 0;} ul, li {list-style: none;} #app {width: 800px; margin: 20px auto; border:1px solid #ccc; border-bottom: none;} #app li {height: 32px; line-height: 32px; border-bottom: 1px solid #ccc;} #app li.bgColor {background-color: red;} </style> </head> <body> <div id='app'> <ul> <li v-for="(item, index) in items" @mouseenter.stop="handleMouseIn(index)" @mouseleave.stop="handleMouseOut(index)" :class="rowClasses(index)" > <span>{{item.name}}</span> </li> </ul> </div> </body> <script src="https://tugenhua0707.github.io/vue/vue1/vue.js"></script> <script type="text/javascript"> new Vue({ el: '#app', data: { items: [ {name: 'kongzhi'}, {name: 'longen'}, {name: 'tugenhua'} ] }, computed: { }, methods: { rowClasses (index) { return [ { [`bgColor`]: this.$data.items[index] && this.$data.items[index]._isHover } ] }, handleMouseIn(index) { if (this.$data.items[index]._isHover) { return; } console.log(111); // 可以執行到 this.$data.items[index]._isHover = true; this.$data.items = Object.assign({}, this.$data.items); }, handleMouseOut(index) { this.$data.items[index]._isHover = false; this.$data.items = Object.assign({}, this.$data.items); } } }); </script> </html>
2. 使用Vue.set(object, key, value)方法將響應屬性添加到嵌套的對象上。
鼠標移動上去的時候 代碼可以改成如下:
this.$set(this.$data.items[index], '_isHover', true);
鼠標移出的時候,代碼改成如下:
this.$set(this.$data.items[index], '_isHover', false);
所有的代碼如下:
<!DOCTYPE html> <html> <head> <title>演示Vue</title> <style> * {margin: 0; padding: 0;} ul, li {list-style: none;} #app {width: 800px; margin: 20px auto; border:1px solid #ccc; border-bottom: none;} #app li {height: 32px; line-height: 32px; border-bottom: 1px solid #ccc;} #app li.bgColor {background-color: red;} </style> </head> <body> <div id='app'> <ul> <li v-for="(item, index) in items" @mouseenter.stop="handleMouseIn(index)" @mouseleave.stop="handleMouseOut(index)" :class="rowClasses(index)" > <span>{{item.name}}</span> </li> </ul> </div> </body> <script src="https://tugenhua0707.github.io/vue/vue1/vue.js"></script> <script type="text/javascript"> new Vue({ el: '#app', data: { items: [ {name: 'kongzhi'}, {name: 'longen'}, {name: 'tugenhua'} ] }, computed: { }, methods: { rowClasses (index) { return [ { [`bgColor`]: this.$data.items[index] && this.$data.items[index]._isHover } ] }, handleMouseIn(index) { if (this.$data.items[index]._isHover) { return; } console.log(111); // 可以執行到 this.$set(this.$data.items[index], '_isHover', true); }, handleMouseOut(index) { this.$set(this.$data.items[index], '_isHover', false); } } }); </script> </html>