1、背景
今天要讲的内容是Web前端框架vue.js中的一个细节,注意是细节哦,稍不留神就掉坑里了。
由于这两天在公司开发前端vue页面,踩到了一个坑,这个坑不大不小的,但是对于我这种除非公司需要,否则不会主动学习前端技术的后端开发者来说,这个坑困扰了我半天时间。无论怎么修改代码,还是实现不了效果,归根结底还是没有找到问题的点所在。
凡事都有好的一面,今天上午脑子就开了光,思路比昨天下午清晰多了,顺着思路,我终于发现了问题的点所在,然后百度一搜,果然是这样,嗨!于是我决定总结一番!
大家都知道,vue的核心特性是数据动态双向绑定,但是数据绑定背后的原理是什么呢,这个有必要了解一番。
2、VUE核心原理
当你将一个普通的js对象作为vue的数据时,vue会遍历该对象的所有属性,并通过Object.defineProperty()方法将这些属性全部转化为getter/setter。defineProperty()是js标准内置对象Object的一个方法,用于直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。这句话有点抽象,先来看一下该方法的语法。
2.1、Object.defineProperty()
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()方法可以这么用。
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。例如:
var vm = new Vue({
data:{
a:1
}
});
//vm.a是响应式的
vm.b = 2
//vm.b是非响应式的
对于已经创建的实例,Vue 不允许动态添加根级别的响应式 property。但是,可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式 property。例如:
Vue.set(vm.someObject, 'b', 2)
您还可以使用 vm.$set 实例方法,这是全局 Vue.set 方法的别名:
this.$set(this.someObject,'b',2)
3.2、对于数组
Vue 不能检测以下数组的变动:
-
当你利用索引直接设置一个数组项时,例如:vm.array[index] = newValue
-
当你修改数组的长度时,例如:vm.array.length = newLength
举个栗子:
var vm = new Vue({
data: {
array: ['a', 'b', 'c']
}
});
vm.array[1] = 'x' //不是响应性的
vm.array.length = 2 //不是响应性的
为了解决第一类问题,以下三种方式都可以实现和 vm.array[index] = newValue 相同的效果,同时也将在响应式系统内触发状态更新:
// 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:
vm.array.splice(newLength)
今天的文章详解vue双向绑定原理分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/5923.html