首页 > 代码库 > 一个简单的MVVM雏形

一个简单的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>