双向数据绑定

双向数据绑定如何实现的

  • 脏检查: angular.js内部会维护一个序列,将所有需要监控的属性放在这个序列中,当发生某些特定事件时,angular会调用$digest方法,这个方法的内部的逻辑就是遍历所有的watcher,对被监控的属性做对比,如果发生变化,调用响应的handler。缺点很明显,性能很差,特别当监控数量达到一个数量级的时候
  • 观察机制 Obeject.observe(),缺点支持度不行
  • 封装属性访问器 vue.js
  • 访问器属性
  • ![enter description here][2]
  • 访问器属性比较特殊,读取或设置访问器属性的值,实际上是调用其内部特性:get和set
  • vue采用的是数据劫持+发布者订阅者方式实现双向数据绑定的,通过object.defineProperty()劫持各个属性的get和set方法,在数据变动时发布消息给订阅者,触发相应的监听回调

vue实现双向数据绑定的代码

function compile (node, vm) {
    var reg = /\{\{(.*)\}\}/;
    //节点类型为元素
    if (node.nodeType === 1) {
        var attr = node.attributes;
        for (var i=0;i<attr.length;i++) {
            if (attr[i].nodeName == 'v-model') {
                var name = attr[i].nodeValue;
                node.addEventListener('keyup', function (e) {
                    vm[name] = e.target.value;
                });
                node.value = vm.data[name];
                node.removeAttribute('v-model');
            }
        }
    }

    //节点类型为text
    if (node.nodeType === 3) {
        if (reg.test(node.nodeValue)) {
            var name = RegExp.$1;//获取到匹配的字符串
            name = name.trim();
            //node.nodeValue = vm.data[name];
            new Watcher(vm, node, name);
        }
    }
}

function Watcher (vm, node, name) {
    Dep.target = this;
    this.name = name;
    this.node = node;
    this.vm = vm;
    this.update();
    Dep.target = null;
}
Watcher.prototype = {
    update: function () {
        this.get();
        this.node.nodeValue = this.value;
    },
    get: function () {
        this.value = this.vm[this.name];
    }
}
function nodeToFragment (node, vm) {
    var flag = document.createDocumentFragment();
    var child;
    while (child = node.firstChild) {
        compile(child, vm);
        flag.appendChild(child);
    }
    return flag;
}
function defineReactive (obj, key, val) {
    var dep = new Dep();
    Object.defineProperty(obj, key, {
        get: function () {
            if (Dep.target) {
                dep.addSub(Dep.target);
            }
            return val;
        },
        set: function (newVal) {
            if (newVal === val) return;
            val = newVal;
            dep.notify();
        }
    });
}

function observe (obj, vm) {
    Object.keys(obj).forEach(function (key) {
        defineReactive(vm, key, obj[key]);
    });
}

function Vue (options) {
    this.data = options.data;
    var data = this.data;
    observe(data, this);
    var id = options.el;
    var dom = nodeToFragment(document.getElementById(id), this);
    document.getElementById(id).appendChild(dom);
}
function Dep () {
    this.subs = [];
}

Dep.prototype = {
    addSub: function (sub) {
        this.subs.push(sub);
    },
    notify: function () {
        this.subs.forEach(function (sub) {
            sub.update();
        });
    }
}
var vm = new Vue({
    el: 'app',
    data: {
        text: 'hello world'
    }
})
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值