Vue原理

MVVM原理

数据驱动视图

  • Vue-mvvm
  • React-setState

MVVM

Model Vue Vue Model

Vue响应式

  • Vue2中使用Object.defineProperty()
    • 如果对象里有数组,数组更改无法劫持
    • 新增对象属性无法触发视图更新
  • Vue3使用Proxy() 兼容性不好 也无法polyfill

defineProperty基本用法

监听简单对象

    const data = {};
    const name = "lc";
    Object.defineProperty(data, "name", {
        get: function () {
            console.log("get...");
            return name;
        },
        set: function (newVal) {
            console.log("set...");
            name = newVal
        }
    });
    console.log(data);

Vue原理_第1张图片

深度监听

  • 需要递归到底,一次性计算量大
  • 无法监听新增属性/删除属性(Vue.set/Vue.delete)
// 触发更新视图
function updateView() {
    console.log('视图更新');
}

// 重新定义属性,监听起来
function defineReactive(target, key, value) {
    // 深度监听
    observer(value);

    // 核心 API
    Object.defineProperty(target, key, {
        get() {
            console.log("get...");
            return value;
        },
        set(newValue) {
            console.log("set...");
            if (newValue !== value) {
                // 深度监听
                observer(newValue);

                // 设置新值
                // 注意,value 一直在闭包中,此处设置完之后,再 get 时也是会获取最新的值
                value = newValue;

                // 触发更新视图
                updateView();
            }
        }
    });
}

// 监听对象属性
function observer(target) {
    if (typeof target !== 'object' || target === null) {
        // 不是对象或数组
        return target;
    }

    // 重新定义各个属性(for in 也可以遍历数组)
    for (let key in target) {
        defineReactive(target, key, target[key]);
    }
}

// 准备数据
const data = {
    name: 'lc',
    age: 20,
    info: {
        address: '成都' // 需要深度监听
    },
};

// 监听数据
observer(data);

// 测试
console.log(data);


监听数组

// 重新定义数组原型
const oldArrayProperty = Array.prototype;
// 创建新对象,原型指向 oldArrayProperty ,再扩展新的方法不会影响原型
const arrProto = Object.create(oldArrayProperty);
// 对数组扩展新的方法
['push', 'pop', 'shift', 'unshift', 'splice'].forEach(methodName => {
    arrProto[methodName] = function () {
        updateView(); // 触发视图更新
        oldArrayProperty[methodName].call(this, ...arguments);
        // Array.prototype.push.call(this, ...arguments)
    };
});
console.log(arrProto);

Vue原理_第2张图片

// 触发更新视图
function updateView() {
    console.log('视图更新');
}

// 重新定义数组原型
const oldArrayProperty = Array.prototype;
// 创建新对象,原型指向 oldArrayProperty ,再扩展新的方法不会影响原型
const arrProto = Object.create(oldArrayProperty);
// 对数组扩展新的方法
['push', 'pop', 'shift', 'unshift', 'splice'].forEach(methodName => {
    arrProto[methodName] = function () {
        updateView(); // 触发视图更新
        oldArrayProperty[methodName].call(this, ...arguments);
        // Array.prototype.push.call(this, ...arguments)
    };
});
console.log(arrProto);

// 重新定义属性,监听起来
function defineReactive(target, key, value) {
    // 深度监听
    observer(value);

    // 核心 API
    Object.defineProperty(target, key, {
        get() {
            console.log("get...");
            return value;
        },
        set(newValue) {
            console.log("set...");
            if (newValue !== value) {
                // 深度监听
                observer(newValue);

                // 设置新值
                // 注意,value 一直在闭包中,此处设置完之后,再 get 时也是会获取最新的值
                value = newValue;

                // 触发更新视图
                updateView();
            }
        }
    });
}

// 监听对象属性
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]);
    }
}

// 准备数据
const data = {
    name: 'lc',
    age: 20,
    info: {
        address: '成都' // 需要深度监听
    },
    arr: [10, 20, 30]
};

// 监听数据
observer(data);

// 测试
console.log(data);

Vue原理_第3张图片
在这里插入图片描述

虚拟DOM

  • DOM操作非常耗费性能
  • vdom用JS模拟DOM结构,计算出最小的变更来操作DOM

diff算法

  • 是vdom的核心部分
  • key值就是diff的一个体现

两棵DOM树作对比

树diff的事件复杂度O(n^3)

  1. 遍历tree1,
  2. 遍历tree2
  3. 排序

时间复杂度太高,算法不可用

优化复杂度到O(n)

  • 只比较同一层,不跨级比较
  • tag不相同,直接删除重建,不再深度比较
    Vue原理_第4张图片
  • tag和key两者都相同,则认为是相同节点,不再深度比较

你可能感兴趣的:(Vue)