vue的双向绑定原理_vue2双向绑定原理

2022-11-02 17:03:07 浏览数 (1)

1、背景

今天要讲的内容是Web前端框架vue.js中的一个细节,注意是细节哦,稍不留神就掉坑里了。

由于这两天在公司开发前端vue页面,踩到了一个坑,这个坑不大不小的,但是对于我这种除非公司需要,否则不会主动学习前端技术的后端开发者来说,这个坑困扰了我半天时间。无论怎么修改代码,还是实现不了效果,归根结底还是没有找到问题的点所在。

凡事都有好的一面,今天上午脑子就开了光,思路比昨天下午清晰多了,顺着思路,我终于发现了问题的点所在,然后百度一搜,果然是这样,嗨!于是我决定总结一番!

大家都知道,vue的核心特性是数据动态双向绑定,但是数据绑定背后的原理是什么呢,这个有必要了解一番。

2、VUE核心原理

当你将一个普通的js对象作为vue的数据时,vue会遍历该对象的所有属性,并通过Object.defineProperty()方法将这些属性全部转化为getter/setter。defineProperty()是js标准内置对象Object的一个方法,用于直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。这句话有点抽象,先来看一下该方法的语法。

2.1、Object.defineProperty()

代码语言:javascript复制
Object.defineProperty(obj, prop, descriptor)
  • obj:对象
  • prop:对象的某个属性
  • descriptor:属性描述符

属性描述符有以下可选方案:

  • configurable:当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除,默认为 false
  • enumerable:当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中,默认为 false
  • value:该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等),默认为 undefined
  • writable:当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符改变,默认为 false
  • get:属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值,默认为 undefined
  • set:属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象,默认为 undefined

通过上面的介绍,我们了解到了Object.defineProperty()方法可以这么用。

代码语言:javascript复制
Object.defineProperty(user, "name", {get() { return value; },  set(newValue) { value= newValue; },  configurable : true,  value: "小明"  });

关于Object.defineProperty()更深层次的介绍请戳这里 Object.defineProperty() – JavaScript | MDN

2.2、组件渲染

Object.defineProperty()说完了,接下来继续聊聊vue的响应式原理。前面说到Object.defineProperty()方法将这些属性全部转化为getter/setter,而这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。

每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。这种关系可以用下图表示。

3、脱坑关键

说完了上面的vue核心原理,下面聊聊标题:vue不能动态监测对象属性的问题!

由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。一听到这,是不是觉得没法玩了?不要慌,问题总是有解决办法滴!下面就聊聊解决办法!

3.1、对于对象

Vue 无法检测 property的添加或移除。由于 Vue 会在初始化实例时对 property 执行 getter/setter 转化,所以 property 必须在对象上存在才能让 Vue 将它转换为响应式的。例如:

对于已经创建的实例,Vue 不允许动态添加根级别的响应式 property。但是,可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式 property。例如:

代码语言:javascript复制
var vm = new Vue({
  data:{
    a:1
  }
});
//vm.a是响应式的

vm.b = 2
//vm.b是非响应式的

对于已经创建的实例,Vue 不允许动态添加根级别的响应式 property。但是,可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式 property。例如:

代码语言:javascript复制
Vue.set(vm.someObject, 'b', 2)

您还可以使用 vm.$set 实例方法,这是全局 Vue.set 方法的别名:

代码语言:javascript复制
this.$set(this.someObject,'b',2)

3.2、对于数组

Vue 不能检测以下数组的变动:

  • 当你利用索引直接设置一个数组项时,例如:vm.array[index] = newValue
  • 当你修改数组的长度时,例如:vm.array.length = newLength

举个栗子:

代码语言:javascript复制
var vm = new Vue({

  data: {
    array: ['a', 'b', 'c']
  }
});

vm.array[1] = 'x' //不是响应性的
vm.array.length = 2 //不是响应性的

为了解决第一类问题,以下三种方式都可以实现和 vm.array[index] = newValue 相同的效果,同时也将在响应式系统内触发状态更新:

代码语言:javascript复制
// Vue.set
Vue.set(vm.array, index, newValue)

// Array.prototype.splice
vm.array.splice(index, 1, newValue)

//vm.$set
vm.$set(vm.array, index, newValue)

为了解决第二类问题,你可以使用 splice:

代码语言:javascript复制
vm.array.splice(newLength)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/180726.html原文链接:https://javaforall.cn

0 人点赞