简单实现vue双向数据绑定

Vue 的响应式原理是核心是通过 ES5 的保护对象的 Object.defindeProperty 中的访问器属性中的 get 和 set 方法,data 中声明的属性都被添加了访问器属性,当读取 data 中的数据时自动调用 get 方法,当修改 data 中的数据时,自动调用 set 方法,检测到数据的变化,会通知观察者 Wacher,观察者 Wacher自动触发重新render 当前组件(子组件不会重新渲染),生成新的虚拟 DOM 树,Vue 框架会遍历并对比新虚拟 DOM 树和旧虚拟 DOM 树中每个节点的差别,并记录下来,最后,加载操作,将所有记录的不同点,局部修改到真实 DOM 树上。

 

 虚拟DOM (Virtaul DOM): 用 js 对象模拟的,保存当前视图内所有 DOM 节点对象基本描述属性和节点间关系的树结构。用 js 对象,描述每个节点,及其父子关系,形成虚拟 DOM 对象树结构。

 

简单实现vue双向数据绑定:

<!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>
    <input id="inp" type="text">
    <span id="spanEle"></span>

</body>
<script>
    let inpEle = document.getElementById('inp');
    let spanEle = document.getElementById('spanEle');

    inpEle.addEventListener('input', function () {
        data.name = inpEle.value;
    })

    function render() {
        spanEle.innerHTML = JSON.stringify(data);
    }
    let data = {
        name: '请输入你的姓名',
        location: { x: 100, y: 100 }
    }
    inpEle.value = data.name;
    observe(data)
    function observe(obj) { // 数据劫持
        // 判断类型
        if (!obj || typeof obj !== 'object') {
            return
        }
        Object.keys(obj).forEach(key => {
            defineReactive(obj, key, obj[key])
        })
        function defineReactive(obj, key, value) {
            // 递归子属性
            observe(value)
            Object.defineProperty(obj, key, {
                enumerable: true, //可枚举(可以遍历)
                configurable: true, //可配置(比如可以删除)
                get: function reactiveGetter() {
                    console.log('get:', value) // 监听
                    return value
                },
                set: function reactiveSetter(newVal) {
                    observe(newVal) //如果赋值是一个对象,也要递归子属性
                    if (newVal !== value) {
                        value = newVal
                        render()
                        console.log('set:', newVal) // 监听

                    }
                }
            })
        }
    }

    setTimeout(() => {
        data.location = {
            x: { xx: { xxx: 2020 } },
            y: 2020
        }
        console.log(data.name);
    }, 1000)

    setTimeout(() => {
        data.location.x.xx.xxx = 0823;
    }, 4000)

</script>

</html>

 

posted @ 2020-04-20 17:59  阿伮  阅读(466)  评论(0编辑  收藏  举报