vue的响应式实现原理

vue2.0的双向数据绑定主要实现方式就是: 发布订阅 + 数据劫持

这里来手写一个实现过程,

// 发布订阅 + 数据劫持

// 订阅器模型

let Dep = {
    // 容器
    clientList: {}, // 为何不是数组? 深拷贝与浅拷贝,使用数组需要key来进行查值
    // 添加订阅者
    listen: function (key, fn) {
        // 短路运算
        (this.clientList[key] || (this.clientList[key] = [])).push(fn)
    },
    // 发布消息
    trigger: function () {
        // 类数组转换为数组
        let key = Array.prototype.shift.call(arguments),
            fns = this.clientList[key];
        if (!fns || fns.length === 0) {
            return false;
        }
        // vue 源码写法
        for (let i = 0, fn; fn = fns[i++];) {
            fn.apply(this, arguments);
        }
    }
}

// 数据劫持
let dataHijack = function ({
    data,
    tag,
    datakey,
    selector
}) {
    let value = '',
        el = document.querySelector(selector);
    Object.defineProperty(data, datakey, {
        get: function () {
            console.log("在这里获取值!");
            return value;
        },
        set: function (newValue) {
            console.log("在这里设置值!");
            value = newValue;
            Dep.trigger(tag, newValue);
        }
    });
    Dep.listen(tag, function (text) {
        el.innerHTML = text;
    });
}

将js引入html中,

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    可订阅视图1 <span class="box-1"></span>
    可订阅视图2 <span class="box-2"></span>
    <script src="./index.js"></script>
    <script>
        let dataObj = {};
        dataHijack({
            data: dataObj,
            tag: 'view-1',
            datakey: 'one',
            selector: '.box-1'
        });
        dataHijack({
            data: dataObj,
            tag: 'view-2',
            datakey: 'two',
            selector: '.box-2'
        });
        dataObj.one = "小";
        dataObj.two = "大";
    </script>
</body>

</html>

打开浏览器console面板,键入 dataObj.one = "路飞"; dataObj.two = "索隆"; 就可以看到页面发生的变化了。

这里说一下我遇到的问题,Uncaught TypeError: Object.defineProperty called on non-object

报错原因是,给Object.defineProperty传参的数据类型不对,

最后在html里面,发现dataObj定义的是字符串,而不是对象,这里是需要一个对象类型的。

猜你喜欢

转载自blog.csdn.net/vampire10086/article/details/109510466