vue源码学习记录

173 阅读1分钟

vue的核心目的 减少DOM的渲染次数

编译

编译分为三个阶段

1、parse

使用正则解析template中的vue指令(v-xxx)变量等等 形式语法树AST

2、optimize

标记一些静态节点,用作后面的性能优化,在diff的适合直接略过

3、generate

把第一部分的AST转化为渲染函数 render function

例如:
{
    tag: 'div',
    props:{
        name: '开始',
        style:{color: red},
        onClick: xxx
    },
    children:[
        {
            tag: 'a',
            text: 'click me'
        }
    ]
}
<div name='开始' style='color: red' @click='xxx'>
    <a>
        click me
    </a>
</div>

双向数据绑定简单原理实现

<body>
    <!-- 响应式数据 -->
    <div id="app">
        <p id="name"></p>
    </div>

    <script>
        var obj = {

        }

        Object.defineProperty(obj, 'name',{
            get:function(){
                return document.querySelector('#name').innerHTML;
            },
            set:function(val){
                document.querySelector('#name').innerHTML=val
            }
        })

        obj.name='这是数据渲染'
    </script>
</body>

简易实现数据更新提示

kvue.js
class Kvue {
    constructor(options){
        this.$optons=options

        // 数据响应化
        this.$data = options.data;

        this.observe(this.$data)
    }

    observe(value){
        if(!value || typeof value !== 'object'){
            return;
        }

        // 遍历对象
        Object.keys(value).forEach(key=>{
            this.defineReactive(value,key,value[key])
        })
    }

    // 数据的响应化
    defineReactive(obj, key, val ){
        
        this.observe(val)
        
        const dep = new Dep()
        
        Object.defineProperty(obj,key,{
            get(){
                return val
            },
            set(newVal){
                if(newVal === val){
                    return;
                }

                val = newVal;
                //console.log('属性发生变化啦')
                dep.notify();
            }
        })
    }
}


//Dep: 用来管理Watcher
class Dep {
    constructor(){
        //这是存放的是诺干的依赖(watcher)
        this.deps=[] ;
    }
    //添加依赖
    addDep(dep){
        this.deps.push(dep)
    }
    
    //通知依赖更新
    notify(){
        this.deps.forEach(dep => dep.update() )
    }
}

//Watcher
class Watcher {
    constructor (){
    //将当前的watcher实例指定到Dep静态属性target
        Dep.target = this;
    }
    update(){
        console.log('数据更新了')
    }
}
<body>
    <script src="./kvue.js"></script>
    <script>
        const app=new Kvue({
            data:{
                test: 'I am is cui',
                foo: {
                    msg: 'this is mi'
                }
            }
        })    

        app.$data.test= '这是数据响应化'
        app.$data.foo.msg= '这是响应化数据'
    </script>
</body>

数据劫持的步骤:利用Object.defineProperty属性,每一个属性都定义了 get和set方法,当这些数据发生改变时,通知其所在的视图发生相应的改变