赞
踩
1. 利用Object.defineProperty+递归 实现响应式原理
- // 监听数组, Object.defineProperty做不到, 所以需要重写数组方法!!!
- // 重新定义数组原型
- const oldArrProperty = Array.prototype
- // 创建新对象, 原型指向oldArrProperty, 再扩展新的方法不会影响Array原型
- // 使用Object.create是为了不污染全局的原型方法
- const arrProto = Object.create(oldArrProperty);
- ['push', 'pop', 'shift', 'unshift', 'splice'].forEach(element => {
- arrProto[element] = function () {
- updateView(); // 触发视图更新
- oldArrProperty[element].call(this, ...arguments);
- }
- });
-
- // 监听对象属性
- function observer(target) {
- if (typeof target !== 'object' || target === null) {
- // 不是对象或数组
- return target;
- }
-
- if (Array.isArray(target)) {
- target.__proto__ = arrProto
- }
-
- // 重新定义各个属性(for in 也可以遍历数组)
- for (let key in target) {
- defineReactive(target, key, target[key])
- }
- }
-
- // 重新定义属性, 监听起来
- function defineReactive(target, key, value) {
- // 深度监听(深层对象):
- observer(value);
-
- // 核心API
- Object.defineProperty(target, key, {
- get() {
- return value
- },
- set(newVal) {
- if (newVal !== value) {
- // 设置新值的时候也要深度监听(深层对象):
- observer(newVal)
- // 设置新值
- // 注意, value一直闭包中, 此处设置完之后, 再get时也是会获取最新的值
- value = newVal
-
- // 触发更新视图
- updateView();
- }
- }
- })
- }
-
- // 触发更新视图
- function updateView() {
- console.log('视图更新')
- }
- const data = {
- name: 'zhangsan',
- age: 20,
- info: {
- city: '北京', // 需要深度监听
- },
- nums: []
- }
-
- // 监听数据
- observer(data)
-
- //测试
- // data.name='sdhewifewfewfewf'
- // data.age = 21
- // data.info.city = 'shanghai'
- // data.x = '100';//新增属性, 监听不到--所以有V
- // delete data.name; // 删除属性, 监听不到 --所以有Vue.delete
- data.nums.push({ a: 1 }); // 监听数组
- data.nums[0].a = 222
- // console.log(data.name, data.age, data.info.city, data.nums)
-
-
- // console.log(arrProto)
- // console.log(arrProto.__proto__.push)
- // console.log(arrProto.__proto__ === oldArrProperty)
- // console.log(arrProto.prototype.constructor)
测试: 每次修改数据, 查看控制台有没有随着数据变化打印"视图更新"
2. 使用Proxy和Reflect实现响应式原理, 如果有深层对象和数组也需要递归
- var data = {
- name: 'zhangsan',
- age: 20,
- list: [1, 2],
- obj: { a: 1, b: 2, c: 2, city: {
- name: '北京'
- }}
- }
-
- function reactive(data) {
- const config = {
- // receiver其实指的就是Proxy
- get(target, key, receiver) {
- // Reflect.ownKeys可以获取不是原型上的属性
- const ownKeys = Reflect.ownKeys(target);
- // 只处理本身(非原型的)属性
- // if(ownKeys.includes(key)) {
- // console.log('get:', key, '本身(非原型的)属性');
- // }
- const result = Reflect.get(target, key, receiver);
- // 如果对象有深层的对象或者数组, 需要递归
- if(Array.isArray(result) || Object.prototype.toString.call(result) === '[object Object]') {
- return reactive(result);
- }
- console.log('get:', key, target[key], result)
- return result;
- },
- set(target, key, val, receiver) {
- // 重复的数据不处理
- const oldVal = target[key]
- if(val === oldVal) {
- return true
- }
-
- const ownKeys = Reflect.ownKeys(target);
- // 只处理本身(非原型的)属性
- if(ownKeys.includes(key)) { // push方法就不执行了
- console.log('get:', key, '已有的key');
- }
- else {
- console.log('get:', key, '新增的key');
- }
-
- const result = Reflect.set(target, key, val, receiver);
- console.log('set:', key, val, result)
- // 触发更新视图
- updateView();
- return result;
- },
- deleteProperty(target, key) {
- const result = Reflect.deleteProperty(target, key);
- console.log('deleteProperty:', key, result)
- // 触发更新视图
- updateView();
- return result;
- },
- }
- const proxyData = new Proxy(data, config);
- return proxyData
- }
-
- // 触发更新视图
- function updateView() {
- console.log('视图更新')
- }
-
- const proxyData = reactive(data)
- proxyData.list.push('13')
- proxyData.obj.a = 999
- proxyData.obj.b = undefined
- proxyData.obj.city.name = 'shanghai'
- Reflect.deleteProperty(proxyData.obj, 'c')
- proxyData.obj.d = 'ddddd'
测试: 每次修改数据, 查看控制台有没有随着数据变化打印"视图更新"
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。