Vue2数据发生变化到页面变化基本流程(附简单实现)

Vue的数据改变

在这里插入图片描述
原理

  • 先将数据进行Obj.definedProperty() 进行绑定 , 判断数据为数组或者对象进行绑定
  • 当页面开始渲染会定义updateComponent方法,这个方法主要就是为了调用render方法
  • 进入render的时候会执行页面使用的值,这时候会触发该数据的get属性
  • 开始进行绑定依赖,大概如图示

在这里插入图片描述

  • 之后通过patch方法将节点进行更新替换或者新增
  • 如果数据发生改变,会执行数据的set方法,这时候数据的Dep.notify会调用
  • Dep.notify 回去调用绑定的Watcher,促使他更新,并且收集所有改变,一次性进行改变
  • 调用Watcher的 run()方法,run方法会调用updateComponent方法进行render`更新
  • 在这里插入图片描述
  • 简单实现代码如下

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id='text'>o.b</div>
    <script>
        // Watcher
        class Watcher {
            constructor(updateComponent) {
                this.newDepIds = new Set()
                this.newDeps =  []
                this.depIds = new Set()
                this.getter = updateComponent;
                this.get()
                
            }
            addDep(dep) {
                const id = dep.id
                if (!this.newDepIds.has(id)) {
                    // watcher保存和它有关的dep
                    this.newDepIds.add(id)
                    this.newDeps.push(dep)
                    // 反过来
                    if (!this.depIds.has(id)) {
                        dep.addSub(this)
                    }
                }
            }
            get(){
                setTarget(this)
                this.getter.call()
                removeTarget(this)
            }
            update(){
                this.get()
            }
        }


        //Dep
        var uid = 0
        class Dep {
            constructor() {
                this.id = uid++;
                this.subs = []
            }
            addSub(Watcher) {
                this.subs.push(Watcher)
            }
            depend(){
                Dep.target.addDep(this)
            }
            notify(){
                for (let i = 0, l = this.subs.length; i < l; i++) {
                    this.subs[i].update()
                }
            }
        }
        function setTarget(Watcher) {
            Dep.target = Watcher
        }
        function removeTarget(Watcher) {
            Dep.target = null
        }

        
        // Observer
        var data = {
            o: { b: '666' }
        }
        function defineReactive(obj, key, value) {
            // console.log(obj,key)
            const dep = new Dep();
            if (arguments.length == 2) {
                value = obj[key]
            }
            // 递归遍历
            new Observer(obj[key])
            Object.defineProperty(obj, key, {
                enumerable: true,
                configurable: true,
                get: function reactiveGetter() {
                    if(Dep.target){
                        dep.depend()
                    }
                    return value
                },
                set: function reactiveSetter(newVal) {
                    value = newVal
                    dep.notify()
                }
            })
        }
        function Observer(value) {
            if (value instanceof Object) {
                walk(value);
            }
        }
        function walk(obj) {
            const keys = Object.keys(obj)
            for (let i = 0; i < keys.length; i++) {
                defineReactive(obj, keys[i])
            }
        }
        
        //模拟Vue执行的过程 暂时用setTimeout函数
        setTimeout(()=>{
            new Observer(data)
            new Watcher(function updateComponent(){
                // .. render 渲染更新,这里简化了虚拟dom和diff算法的实现
                console.log('...','发生改变继续调用')
                document.getElementById('text').innerText = this.data.o.b
            })
        })
        setTimeout(()=>{
            this.data.o.b = 555
        },2000)
    </script>
</body>

</html>

  • 如果中间有表述错误,请各位大佬指正 😆 😆
  • 2021-12-06 修改 this.dep = new Dep()const dep = new Dep()
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值