• 数据绑定:模型到视图


    Object.defineProperty

    听说vuejs和avalon都是使用这种方式实现的。

    Object.defineProperty最早是由IE8实现的,但是IE8的实现有许多问题而且不能hack。。。所以vuejs才支持IE9+,avalon才使用VBScript这个鬼。

    我们可以在Object.defineProperty里用getter和setter方法来定义对象的属性,这个属性叫存储器属性(JavaScript权威指南的翻译,JavaScript高级程序设计翻译为访问器属性,英文:accessor property)。当读取属性的时候,会调用getter方法,设置属性时,就会调用setter方法。

    所以,setter方法就给了我们无限可能,自然就可以将数据的变化反映到视图上去。我们看一个例子(改自JavaScript高级程序设计的代码):

    html,就一行:

    <div id="bookName"></div>

    js:

    var bookName = document.getElementById('bookName')
    
    var book = {
        _year: 2004,
        edition: 1
    };
    Object.defineProperty(book, "year", {
        get: function(){
            return this._year;
        },
        set: function(newValue){
         if (newValue > 2004) {
              this._year = newValue;
              bookName.textContent = newValue;
              this.edition += newValue - 2004;
            }
        }
    });
    
    book.year = 2005;

    我们定义了一个book对象,并给了他一个year的属性,读取year的返回_year的值,设置year的时候,_year也随之变化,并且给div的textContent也赋上了新值。就这样完成了简单的模型到视图的绑定。

    Object.observe

    接下来我们要祭出ES7的神器了——Object.observe。

    Object.observe(),作为未来ECMAScript标准的一部分,是一个用于异步监听JavaScript对象变化的方法,并且无需使用额外的JavaScript库。它允许监听器接受一个按时间顺序排列的变更记录序列,这些变更记录描述了被监听对象所发生变化的内容的集合。

    不过它的支持情况就没那么让人兴奋了(来自Can I Use):

    它的使用更加简单。

    还是上面的那一条html代码,js现在是这样:

    var book = {
        year: 2004,
        edition: 1
    };
    
    var bookName = document.getElementById('bookName')
    
    function observer(changes) {
        bookName.textContent = changes[0].object[changes[0].name];
    }
    
    Object.observe(book, observer)
    
    book.year = 2005;

    当book的值发生变化的时候,就会触发observer函数,设置div的值。同样完成了数据到模型的绑定。

    脏检查

    Angular和Regular都使用了脏检查。

    脏检查中,都有一个watch方法来监视着数据的变化,检测到数据变化时就会触发监听的回调,在回调里处理相应的逻辑。但是我们如何知道数据变化了呢。

    这里会有一个digest方法,在这个方法里,检查新值和旧值是否相等,如果不相等,就会触发监听回调。一直循环这个过程,直到两者相等。

    框架大多数情况下都会自动进入digest,同时也会暴露接口给用户,自主触发。

    这里有一个简化的实现:

    var Scope = function() {
        this.$$watchers = [];
    }
    
    Scope.prototype.$watch = function(watchExp, listener) {
        this.$$watchers.push({
            watchExp: watchExp,
            listener: listener || function() {}
        });
    }
    
    Scope.prototype.$digest = function() {
        var dirty;
        do {
            dirty = false;
            for(var i = 0; i < this.$$watchers.length; i++) {
                var newValue = this.$$watchers[i].watchExp(),
                    oldValue = this.$$watchers[i].last;
    
                if(oldValue !== newValue) {
                    this.$$watchers[i].listener(newValue, oldValue);
                    dirty = true;
                    this.$$watchers[i].last = newValue;
                }
            }
        } while(dirty);
    }

    (来自AngularJS 数据双向绑定揭秘

    我们可以这样使用,html代码: <input type="text"> 

    js:

    var $scope = new Scope();
    $scope.name = 'zjzhome';
    
    $scope.$watch(function() {
        return $scope.name;
    }, function(newValue, oldValue) {
        console.log('Input value updated - it is now ' + newValue);
        element.value = $scope.name;
    });
    
    var element = document.querySelector('input');
    
    function updateScopeValue() {
        $scope.name = 'Bob';
        $scope.$digest();
    };
    updateScopeValue();

    你会发现input显示为Bob了。

    这里同时也能够进行视图到模型的绑定,只要监听input的keyup事件即可:

    element.onkeyup = function() {
        $scope.name = element.value;
        $scope.$digest();
    }

    MVVM框架中实现远比这些复杂。了解下基本的原理对于迅速的掌握框架的使用也是好的。

  • 相关阅读:
    nth-of-type()的用法
    H5禁止底部横向滚动条,使一个元素居中
    CRM项目-1模型与站点管理
    django-debug-toolbar
    python发送邮件
    os 模块
    Django(三) ORM操作
    Django框架初识
    JS 正则表达式
    前端-高潮 jQuery
  • 原文地址:https://www.cnblogs.com/jiangxiaobo/p/5954027.html
Copyright © 2020-2023  润新知