数据劫持和数据代理笔记

8 篇文章 0 订阅

vue实现原理

vue是通过数据劫持的方式来做到数据绑定的,最核心的方法是通过Object.defineProperty()来实现对数据的劫持,达到数据变动的目的

实现MVVM

整合Observer、compile、和watcher,通过compile来解析编译,利用watcher搭起Observer和compile之间的通信桥梁,达到数据的拜年话—>视图更新—>视图交互变化(input)---->数据双向绑定的效果

MVVM 双向数据绑定 数据劫持+发布者订阅模式(不兼容低版本 Object.defineProperty)
注意:vue不能新增不存在的属性没有get和set方法,不会监控数据的变化
深度响应 因为每次赋予一个新对象增加prototypey

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Com patible" content="ie=edge">
    <title>Document</title>
    <script>
        function Vue(options={}){
            this.$options=options//将所有属性挂在$options上
            var data=this._data=this.$options.data
            observe(data)
            //数据代理
            // this代理了this_data   所以我们可以在源码中使用vue.a     vue._data.a
            for(let key in data){
                Object.defineProperty(data,key,{
                    enumerable:true,
                    get(){
                        return this._data[key]
                    },
                    set(newval){
                        this._data[key]=newval
                    }
                })
            }
        }

        //vue.$options
// 数据劫持
        //观察对象,给对象增加Object.defineProperty
        function Observe(data){
            for(let key in data){
                let dep=new Dep()
                let val=data[key]
                observe(val)//深层对复制
                Object.defineProperty(data,key,{
                    enumerable:true,
                    get(){
                        Dep.target&&dep.addsub(Dep,target)//[watcher]
                        return val
                    },
                    set(newval){//更改值
                        if(val===newval){//设置的值和以前的一样
                            return
                        }
                        val=newval//如果以后获取值的时候,将刚才获得的值再丢回去
                        observe(newval)//深度数 据观察   确保新添加的对象上也能够做到数据劫持
                        dep.show()//让所有的watch的updata方法执行
                    }
                })
            }
        }
        function observe(data){
            if(typeof data!=='object'){
                return
            }
            return new Observe(data)
        }



// 编译模式  插值表达式
function Compile(el,vue){
            //el表表示替换的范围
            vue.$el=document.querySelector(el)
            let fragment=document.createDocumentFragment()
            while(child=vue.$el.firstChild){//将app中的内容移入到内存中
                fragment.appendChild(child)
            }
            replace(fragment)
            function replace(fragment){
                Arrar.from(fragment.childNodes).forEach(function(node){
                let text=node.textContent;
                let reg=/\{\{(.*)\}\}/
                if(node.nodeType===3&&reg.test(text)){
                    let arr=RegExp.$1.split(",")
                    let val=vue//val变成this
                    arr.forEach(function(k){
                        val=val[k]
                    })
//连接视图和数据
                    new Wather(vue,RegExp.$1,function(newval){//该函数需要接受一个新的值
                        node.textContent=text.replace(/\{\{(.*)\}\}/)
                     })
                    node.textContent=text.replace(/\{\{(.*)\}\}/)
                }
                // 实现双向绑定
                if(node.nodeType===1){
                    let nodeAttrs=node.nodeAttrs//获取当前节点的属性
                    Array.from(nodeAttrs).forEach(item=>{
                        let name=item.name
                        let exp=item.value//即在页面上往输入框中添加的内容
                        if(name.indexOf("v-")){
                            node.value=vue[exp]
                        }
                        new Wather(vue,exp,function(newval){
                            node.value=newval//当watcher触发时自动将内容放到输入框内
                        })
                        node.addEventListener("input",function(e){
                            let newVal=e.target.value
                            vue[exp]=newVal
                        })
                    })
                }
                if(node.childNodes){
                    replace(node)
                }
            })
            }
            
            vue.$el.appendChild(fragment)
        }





//发布订阅模式

    function Dep(){
        this.subs=[]
    }
    Dep.prototype.addsub=function(sub){//订阅
        this.subs.push(sub)
    }
    Dep.prototype.show=function(){//发布
        this.subs.forEach(item=>item.updata())
    }


    function Wather(vue,exp,fn){//Watch是一个类,通过它创建的每一个实例都拥有updata方法,并且该方法执行传入的函数
        this.fn=fn
        this.vue=vue
        this.exp=exp//添加到订阅中
        Dep.target=this
        let val=vue
        let arr=exp.split(",")
        arr.forEach(function(k){
            val=val[k]
        })
        Dep.target=null
    }
    Wather.prototype.updata=function(){
        let val=this.vue
        let arr=this.exp.split(",")
        arr.forEach(function(k){
            val=val[k]
        })
        this.fn()
    }
    </script>
    <!-- <script>
        //观察者模式可以写为
        function observer(data){
            for (let key in data){
                let val=data[key]
                if(val!=null&&typeof val ==="object"){
                    observer(val);
                    }
                Object.defineProperty(data,key,{
                    enumerable:true,
                    get(){
                        return val;
                    },
                    set(newval){
                        if(newval===val){
                            return;
                        }
                        val=newval;
                        if(val!=null&&typeof val==="object"){
                            observer(val);
                        }
                    }
                })
            }
        }
    </script> -->
    <script>
        let vue=new Vue({
            el:"app",
            data:{a:1}
        })
        
    </script>
</head>
<body>
    <input type="text" v-model="a">
    
</body>
</html>

<!-- vue不能新增不存在的属性没有get和set方法,不会监控数据的变化
深度响应   因为每次赋予一个新对象增加prototypey -->
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值