欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

VUE 使用注意事项:

程序员文章站 2022-07-14 20:38:16
...

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