zoukankan      html  css  js  c++  java
  • vue数据双向绑定原理

    vue的数据双向绑定的小例子:

    。html

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset=utf-8>
        <title>vue数据双向绑定原理</title>
    </head>
    <body>
        <h1 id="name"><<<<name>>>>>></h1>
    </body>
    <script src="testvuejs/observer.js"></script>
    <script src="testvuejs/watcher.js"></script>
    <script src="testvuejs/index.js"></script>
    <script type="text/javascript">
        var ele = document.querySelector('#name');
        var selfVue = new SelfVue({
            name: 'hello world'
        }, ele, 'name');
        window.setTimeout(function () {
            console.log('name值改变了');
            selfVue.name = 'canfoo';
        }, 2000);
    </script>
    </html>

    index.js

    function SelfVue (data, el, exp) {
        var self = this;
        this.data = data;
    
        //把data里的key直接绑定到this对象上
        Object.keys(data).forEach(function(key) {
            self.proxyKeys(key);
        });
    
        //对data的每一层级的属性进行监听,如果变化执行notify
        observe(data);
    
        // 初始化模板数据的值
        el.innerHTML = this.data[exp];  
        
        new Watcher(this, exp, function (value) {
            el.innerHTML = value;
        });
        return this;
    }
    
    SelfVue.prototype = {
        proxyKeys: function (key) {
            Object.defineProperty(this, key, {
                enumerable: false,
                configurable: true,
                get: ()=> {
                    return this.data[key];
                },
                set: (newVal)=> {
                    this.data[key] = newVal;
                }
            });
        }
    }

    observer.js

    function Observer(data) {
        this.data = data;
        this.walk(data);
    }
    Observer.prototype = {
        walk: function(data) {
            var self = this;
            Object.keys(data).forEach(function(key) {
                self.defineReactive(data, key, data[key]);
            });
        },
        defineReactive: function(data, key, val) {
            var dep = new Dep();
            //对二级三级子属性...进行监听尽
            observe(val);
            Object.defineProperty(data, key, {
                enumerable: true,
                configurable: true,
                get: function() {
                    if (Dep.target) {
                        dep.addSub(Dep.target);
                    }
                    return val;
                },
                set: function(newVal) {
                    if (newVal === val) {
                        return;
                    }
                    val = newVal;
                    dep.notify();
                }
            });
        }
    };
    
    function observe(value, vm) {
        if (!value || typeof value !== 'object') {
            return;
        }
        return new Observer(value);
    };
    
    function Dep () {
        this.subs = [];
    }
    Dep.prototype = {
        addSub: function(sub) {
            this.subs.push(sub);
        },
        notify: function() {
            this.subs.forEach(function(sub) {
                sub.update();
            });
        }
    };
    Dep.target = null;

    watcher.js

    function Watcher(vm, exp, cb) {
        this.cb = cb;
        this.vm = vm;
        this.exp = exp;
        //当new一个对象的时候,立即执行get方法,Dep的target为Watcher自己
        this.value = this.get();  // 将自己添加到订阅器的操作
    }
    
    Watcher.prototype = {
        update: function() {
            this.run();
        },
        run: function() {
            var value = this.vm.data[this.exp];
            var oldVal = this.value;
            if (value !== oldVal) {
                this.value = value;
                this.cb.call(this.vm, value);
            }
        },
        get: function() {
            Dep.target = this;  // 缓存自己
            var value = this.vm.data[this.exp]  // this.vm.data[this.exp]:强制执行监听器里的get函数,使自己(Watcher {cb: ƒ, vm: SelfVue, exp: "name"})被添加上
            Dep.target = null;  // 释放自己
            return value;
        }
    };

    原理:当new vue后,将data属性直接给vm添加上,将属性的每一级进行set get 当set新值时通知notify函数。执行 new watcher ,强制执行data的get 使watch被添加上。

    当data set新值时,触发notify函数,使所有watcher都执行update,watcher的update时,本地的value是旧值,取新值,回调函数更新view。

  • 相关阅读:
    css3正方体效果
    单行文本溢出和多行文本溢出变省略号
    iscroll的滑动效果
    angular笔记
    html页面的css样式、meta最常用的最基本最常规的配置参数
    解决webstorm卡顿问题
    pc端网页的设计尺寸
    时间字符串解析成日期时间格式
    Inf2Cat, signability test failed.
    #pragma once 与 #ifndef 解析(转载)
  • 原文地址:https://www.cnblogs.com/wulinzi/p/10408287.html
Copyright © 2011-2022 走看看