VUE 使用注意事項:
阿新 • • 發佈:2018-11-11
VUE 陣列無法觸發檢視更新
首先請看下面程式碼:
new Vue({ el: "#app", data: { todos: [ { text: "Learn JavaScript", done: false }, { text: "Learn Vue", done: false }, { text: "Play around in JSFiddle", done: true }, { text: "Build something awesome", done: true } ] }, methods: { toggle: function(todo){ todo.done = !todo.done }, //檢視會更新 setArr:function(){ this.todos = [ { text: "Learn JavaScript", done: false } ] }, //檢視不會更新 test:function(){ this.todos[0] ={ text: "ok", done: false } }, //通過呼叫VUE 自身$set 方面可觸發手動更新 setTest:function(){ this.$set(this.todos,0,{ text: "ok", done: false }) } }, mounted(){ } })
這個坑要從VUE 實現資料雙向繫結原理說起:
VUE 採用 Object.defineProperty 來攔截監聽資料的變化,而Object.defineProperty只能攔截監聽到某個具體屬性的變化,而攔截不到具體屬性中某個值的變化,下面我通過程式碼來驗證一下:
可見當直接修改todos 屬性時 才會觸發監聽todos 的set 方法進行攔截。如直接修改todos[0]下某個值時無法觸發set,故無法監聽觸發set 方法 導致VUE 的訂閱器無法觸發通知去更新檢視view
var data = { todos: [ { text: "Learn JavaScript", done: false }, { text: "Learn Vue", done: false }, { text: "Play around in JSFiddle", done: true }, { text: "Build something awesome", done: true } ] } var value = '' Object.defineProperty(data, 'todos', { set: function (newValue) { value = newValue; console.log('觸發檢視更新' + JSON.stringify(value)); }, get: function () { return value } }) data.todos = [ { text: "Learn JavaScript", done: false } // 攔截呼叫set方法 你取了一個書名叫做 Object ] console.log(data.todos) //[{ text: "Learn JavaScript", done: false }] data.todos[0] = { text: "ok", done: false } //無法攔截到
我們在手動模擬$set 方法觸發更新一下:
var data = { todos: [ { text: "Learn JavaScript", done: false }, { text: "Learn Vue", done: false }, { text: "Play around in JSFiddle", done: true }, { text: "Build something awesome", done: true } ] } //模擬實現 VUE.$set this.$set(this.todos,0,{ text: "ok", done: false }) let setFuncion = (target, changeKey, values) => { var obj = {}; target.forEach((item,key)=>{ /** * Object.defineProperty 只能監聽物件 所以首先將陣列轉換成key,val 物件,在進行監聽 */ obj[key] = item; /** * 轉換完成之後 對 物件的key 進行監聽 */ Object.defineProperty(obj, key, { set: function (newValue) { target[changeKey] = newValue console.log('觸發更新檢視' + JSON.stringify(newValue)); }, get: function () { return target[changeKey] } }) }); obj[changeKey] = values } //呼叫set方法,觸發更新檢視{"text":"ok","done":false} setFuncion(data.todos, 0, { text: "ok", done: false }) console.log(data.todos) /* [ { text: "ok", done: false }, { text: "Learn Vue", done: false }, { text: "Play around in JSFiddle", done: true }, { text: "Build something awesome", done: true } ] */