zoukankan      html  css  js  c++  java
  • 数据绑定:模型到视图

    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框架中实现远比这些复杂。了解下基本的原理对于迅速的掌握框架的使用也是好的。

  • 相关阅读:
    Count and Say leetcode
    Find Minimum in Rotated Sorted Array II leetcode
    Find Minimum in Rotated Sorted Array leetcode
    Search in Rotated Sorted Array II leetcode
    search in rotated sorted array leetcode
    Substring with Concatenation of All Words
    Subsets 子集系列问题 leetcode
    Sudoku Solver Backtracking
    Valid Sudoku leetcode
    《如何求解问题》-现代启发式方法
  • 原文地址:https://www.cnblogs.com/jiangxiaobo/p/5954027.html
Copyright © 2011-2022 走看看