vue源码分析之视图连接数据(四)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <div>
        {{a.b}}
    </div>
    <div>
        {{c}}
    </div>
</div>
<script>
    // 判断是不是对象类型
    function isObj(x){
        if(Object.prototype.toString.call(x) == '[object Object]'){
            return true
        }
    }

    function Vue(options){
        this._data = options.data
        observe(this._data)
        // 数据代理
        for(let key in this._data){
            Object.defineProperty(this,key,{
                get(){
                    return this._data[key]
                },
                set(newVal){
                    this._data[key] = newVal
                }
            })
        }
        // 模板编译
        compile(options.el,this)
    }
    function observe(data){
        let dep = new Dep()
        for(let key in data){
            let val = data[key]
            Object.defineProperty(data,key,{
                get(){
                    if(Dep.target){
                        dep.add(Dep.target)
                    }
                    return val
                },
                set(newVal){
                    if(newVal === val){
                        return
                    }
                    val = newVal
                    if(isObj(newVal)){
                        observe(newVal)
                    }
                    dep.run()
                }
            })

            if(isObj(data[key])){
                observe(data[key])
            }
        }
    }
    function compile(el,vue){
        let dom = document.querySelector(el)
        let fragment = document.createDocumentFragment()
        while(child = dom.firstChild){
            fragment.append(child)
        }

        let reg = /\{\{(.*)\}\}/
        replace(fragment)
        function replace(fragment){
            Array.from(fragment.childNodes).forEach(node=>{
                if(node.nodeType === 3 && reg.test(node.textContent)){
                    let text = node.textContent
                    let l = RegExp.$1.split(".")
                    let val = vue
                    l.forEach(item=>{
                        val = val[item]
                    })
                    node.textContent = text.replace(reg,val)

                    new Watch(vue,l,function(newVal){
                        node.textContent = text.replace(/\{\{(.*)\}\}/,newVal)
                    })
                }
                if(node.childNodes){
                    replace(node)
                }
            })
        }
        dom.appendChild(fragment)
    }

    function Dep() {
        this.list = []
    }
    Dep.prototype.add = function(watch) {
        this.list.push(watch)
    }
    Dep.prototype.run = function(){
        this.list.forEach(item=>{
            item.update()
        })
    }

    function Watch(vue,l,fn){
        this.vue = vue
        this.l = l
        this.fn = fn
        Dep.target = this
        let val = vue
        l.forEach(item=>{
            val = val[item]
        })
        //变成null是因为你执行update的时候不会把把watch再放进list
        Dep.target = null
    }
    Watch.prototype.update = function(){
        let val = this.vue
        this.l.forEach(item=>{
            val = val[item]
        })
        this.fn(val)
    }

    let vue = new Vue({
        el:"#app",
        data:{a:{b:1},c:2}
    })
</script>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值