-
1.响应式原理
-
我们在使用 Vue 的时候,赋值属性获得属性都是i直接使用的 Vue 的实例
-
我们在设计属性值的时候,页面的数据更新
-
ES5 语法
-
let o = {} //等价于 let o = {} let value; Object.defineProperty(o, 'age', { //属性访问器 不能和 writable 和 value 共存 // writable: true, //可修改的 configurable: true, //可配置的 enumerable: true, //可枚举的,可被 for in 遍历 // value: 12, //属性值 //属性访问器 get() { //访问时 调用 console.log('访问时 调用'); return value }, set(newValue) { //赋值时 调用 console.log(newValue); //就是 get return 的值 value = newValue; //这样 每次在访问时,就会显示 修改后的 value 值了 } })
2.将对象转换为响应式的
-
但是 同时定义多个全局变量不好,vue 是这样实现的
let o = { name: '张三', age: 15, gender: '女' } function defineReactive(target, key, value, enumerable) { Object.defineProperty(target, key, { enumerable: !!enumerable, get() { console.log(`读取 o 的 ${key}属性`); return value; }, set(newVal) { console.log(`设置 o 的 ${key}属性为${newVal}`); value = newVal } }) } Object.keys(o).forEach((item, i) => { defineReactive(o, item, o[item], true) })
3.对象响应式化
-
但是,如果 数据 中有引用类型呢?
-
let data = { name: '张三', age: 18, course: [{ name: '语文' }, { name: '数学' }, { name: '英语' } ] }; //简化后的版本 function defineReactive(target, key, value, enumerable) { // if (typeof value === 'object' && value != null && !Array.isArray(value)) { // //非数组 的引用类型 // reactify(value) // } Object.defineProperty(target, key, { configurable: true, enumerable: !!enumerable, get() { console.log(`读取 data 的 ${key}属性`); return value; }, set(newVal) { value = newVal; } }); } //将 data 响应式化 function reactify(obj) { //因为 keys 只会遍历 可迭代类型 的数据,其他 不可迭代的 都会返回 空数组,而如果是空数组后面的forEach 是不会执行的 //如果是字符串,使用 keys 也会返回数组,但是一旦进行递归,forEach 也不会执行 let keys = Object.keys(obj) for (let i = 0; i < keys.length; i++) { let key = keys[i]; let value = obj[key]; //判断 if (Array.isArray(value)) { //数组 for (let j = 0; j < value.length; j++) { reactify(value[j]) } } else { //判断方法一 if (typeof value === 'object' && value != null && !Array.isArray(value)) { //非数组 的引用类型 reactify(value) } //判断方法二 // if (Object.prototype.toString.call(value) === '[object Object]') { // //非数组 的引用类型 // reactify(value) // } //这俩方法 可以放在这里,也可以 放在defineReactive 中 defineReactive(obj, key, value, true); } } } reactify(data);
4.扩展函数功能
-
问题:如果 数据 进行 push pop 等变异数组,是不会 defineProperty是不会响应的
-
要怎么做呢?
-
1.在改变数组的时候,要发出通知
-
在Vue2中的缺陷,数组发生变化,设置 length 没发通知(vue3 中使用 proxy(ES6语法)解决了这个问题)
-
-
2.加入的元素应该变成响应式的
-
技巧:如果一个函数已经定义了,但是我们需要扩展其功能,我们一般的处理办法:
-
1.使用一个临时的函数名存储函数
2.重新定义原来的函数
3.定义扩展的功能
4.调用临时的那个函数
//这个就是在函数的原有上增加额外的功能:函数的拦截 function func() { console.log('原始的功能'); } //1.使用一个临时的函数名存储函数 let tempFn = func; //2.重新定义原来的函数 func = function () { //4.调用临时的那个函数 tempFn(); //'原始的功能' //3.定义扩展的功能 console.log('新的扩展的功能'); } func() //1.打印出 '原始的功能' //2.打印出 '新的扩展的功能'
5. 数组的拦截
-
思路:谁要响应化,就拦截谁
继承关系: arr -> Array.prototype -> Object.prototype ->...
改写为: arr -> 改写的方法 -> Array.prototype -> Object.prototype ->...
-
const ARRAY_METHODS = [ 'push', // 'pop', 'shift', 'unshift', 'sort', 'reverse', 'splice' ]; let arr = [] //创建一个 数组原型 let array_methods = Object.create(Array.prototype) ARRAY_METHODS.forEach(method => { array_methods[method] = function () { console.log('调用的是拦截的' + method + '方法'); //调用原来的方法 //将 数据原型中的 this 指向将来 要调用的对象 // arguments 就是这些 数组 方法 中 要使用的 参数 //因为 push pop 等 方法返回。所以接收到一个变量 最后 return 出去 let res = Array.prototype[method].apply(this, arguments); return res; } }) arr.__proto__ = array_methods;
-
-
Vue 响应式原理
最新推荐文章于 2024-08-14 00:29:25 发布
本文详细介绍了Vue响应式的基本原理,从ES5的Object.defineProperty实现数据劫持,到对象和数组的响应式转换,以及如何处理数组变异操作的问题。通过函数拦截扩展数组功能,确保变更能触发视图更新。内容涵盖了Vue数据绑定的核心机制。
摘要由CSDN通过智能技术生成