Ruby's Louvre

每天学习一点点算法

导航

一个简单的MVVM雏形

这是@尚春实现的MVVM,使用定时器轮询,只支持{{}}与input.value的修改。

这只能算是一个玩具,真正的MVVM需要有更复杂的扫描机制,JS解析器,双向绑定链什么的。

<!DOCTYPE html>
<html>
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script>
  <meta charset="utf-8">
  <title>JS Bin</title>
  
</head>
<body>
  <div data-component="input">
    <template>
      <input type="text" name="username" tb-model="username" value="" />
      <span>{{ username }}</span>
    </template>
  </div>
  <script>
var DIRECTIVE_ATTR_MODEL = 'tb-model',
    regMustache = /\{\{\s*(\w+)\s*\}\}/g,
    slice = Array.prototype.slice;

function boot() {
    var components = slice.call(document.querySelectorAll('[data-component]'), 0);
    components.forEach(function (el) {
        var component = el.getAttribute('data-component');
        bootComponent(el, window[component + 'Controller']);
    });
}

function bootComponent(el, controller) {
    var $scope = {},
        elFrag = el.querySelector('template').content.cloneNode(true);
    traverse(elFrag, $scope);
    el.appendChild(elFrag);
    controller($scope);
}

function traverse(root, $scope) {
    for (var el = root.firstChild; el; el = el.nextSibling) {
        parseElement(el, $scope);
        if (el) {
            traverse(el, $scope);
        }
    }
}

function parseElement(el, $scope) {
    if (el.nodeType === 1) {
        // element
        if (el.hasAttribute(DIRECTIVE_ATTR_MODEL)) {
            var model = el.getAttribute(DIRECTIVE_ATTR_MODEL);
            el.removeAttribute(DIRECTIVE_ATTR_MODEL);
            el.addEventListener('input', function () {
                $scope[model] = this.value;        
            });
        }
    } else if (el.nodeType === 3) {
        // text node
        var text = el.textContent,
            tpl = [],
            lastIndex = 0,
            match = regMustache.exec(text);
        while (match) {
            tpl.push(text.substring(lastIndex, regMustache.lastIndex - match[0].length));
            tpl.push({
                type: 'var',
                content: match[1]
            });
            lastIndex = regMustache.lastIndex;
            match = regMustache.exec(text);
        }
        watch($scope, function () {
            text = '';
            tpl.forEach(function (item) {
                text += typeof item === 'string' ? item : $scope[item.content];
            });
            el.textContent = text;
        });
    }
}

function watch($scope, cb) {
    var old = _.cloneDeep($scope),
        timer;
    timer = setInterval(function () {
        if (!_.isEqual($scope, old)) {
            cb($scope, old);
            old = _.cloneDeep($scope);
        }
    }, 50);
}

function inputController($scope) {
    $scope.username = 'spring';
}

boot();
  </script>
</body>
</html>

posted on 2014-06-19 11:10  司徒正美  阅读(1792)  评论(6编辑  收藏  举报