logo头像

爱分享 爱生活 爱编程

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue原理</title>
</head>
<body>
    <script src="./index.js"></script>
    <script>
        let vm = new myVue({
            data: {
                age: 12,
                score: {
                    math: 99,
                    english: 89
                }
            }
        })        
    </script>
</body>
</html>
class myVue {
    constructor(options) {
        this._options = options;
        this.$data = options.data;
        this._initData()
    }
<!-- more -->

    _initData() {
        let data = this.$data
        let keys = Object.keys(data)
        // 数据代理
        // 实现 vm.a 可以拿到 示例中 data的a的值
        for (let index = 0; index < keys.length; index++) {
            Object.defineProperty(this, keys[index], {
                enumerable: true, // 可遍历
                configurable: true, // 可被改写
                get: function proxyGetter() {
                    return data[keys[index]]
                },
                set: function proxySetter(val) {
                    data[keys[index]] = val
                }
            })
        }
        // 数据劫持,data 中的任意数据有变动时 进行劫持
        observe(data)
    }


}
// 判断data是否是基础类型, 递归数data据劫持
function observe(data) {
    // 使用Object.prototype上的原生toString()方法判断数据类型
    // 参考链接:https://blog.csdn.net/u012158998/article/details/86423270
    // 判断 data 属性是否是 数组或者 对象类型
    const type = Object.prototype.toString.call(data)
    if (type !== "[object Array]" && type !== "[object Object]") { // 基础类型无需遍历
        return;
    }

    // 递归处理 数据劫持
    new Observer(data)
}

/**
 * 4. 实现数据劫持工具方法
 * @param {*} obj 要劫持的数据
 * @param {*} objKey 劫持数据的类型
 * @param {*} value  劫持数据的原始值
 */
function defineReactive(obj, objKey, value) {
    // 判断下是否可以继续遍历,由内向外的遍历
    observe(obj[objKey])
    Object.defineProperty(obj, objKey, {
        enumerable: true, // 可遍历
        configurable: true, // 可被改写
        get: function proxyGetter() {
            console.log(`${objKey}取值`);
            return value
        },
        set: function proxySetter(val) {
            console.log(`${objKey}发生了改变`);
            value = val
        }
    })
}
// 
class Observer {
    constructor(data) {
        this._walk(data)
    }

    _walk(data) {
        let keys = Object.keys(data)
        for (let index = 0; index < keys.length; index++) {
            // 针对每一层开始遍历数据并劫持
            defineReactive(data, keys[index], data[keys[index]])
        }
    }
}