1. 程式人生 > >VUE 使用注意事項:

VUE 使用注意事項:

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 }
  ] */