w3ctech

一个简单的mvvm demo-avalon原理

在阅读了avalon源码之后,依照其劫持get&&set及观察者模式,实现的一个model-view-viewModel例子,来帮助大家更好的理解流程mvvm框架avalon

<!DOCTYPE html>
 <html>
     <head>
         <title>部分原理 - 第二版</title>
         <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
     </head>
     <body>
        <!--view-->
        <div id="name">
            {{name}} - {{age}} - {{country}}
        </div>
        <p>选择切换</p>
        <select onChange="change.call(this,event)">
            <option>skipper1-1-China1</option>
            <option>skipper2-2-China2</option>
            <option>skipper3-3-China3</option>
            <option>skipper4-4-China4</option>
            <option>skipper5-5-China5</option>
        </select>
        <script>
            // 观察者
            var eventCenter = {
                events: {},
                // 订阅
                add: function(e, callback) {
                    if(!this[e]) this[e] = []
                    for(var i = 0, len = this[e].length; i < len; i++) {
                        if(this[e][i] === callback) return
                    }
                    this[e].push(callback)
                },
                // 分发事件
                fire: function(e, data) {
                    if(this[e]) {
                        for(var i = 0, len = this[e].length; i < len; i++) {
                            this[e][i](data)
                        }
                    }
                }
            };
            // model
            var model = {};
            // view-model 劫持set & get
            // 不过第三版里面已经用 Object.observe
            function addProp(model, key) {
                Object.defineProperty(model, key, {
                    // get,提取依赖,将视图更新函数添加到观察者侦听队列
                    get: function() {
                        var c = arguments.callee.caller,
                            arg = c.arguments
                        eventCenter.add(key, function() {
                            c.apply(null, arg)
                        })
                        return this["$" + key]
                    },
                    // set,值被修改后,触发视图更新函数
                    set: function(v) {
                        this["$" + key] = v;
                        eventCenter.fire(key, v)
                    }
                })
            }
            addProp(model, "name")
            addProp(model, "age")
            addProp(model, "country")
            // ---
            // view-model扫描
            function scan(element, model) {
                var html = element.innerHTML,
                    all = html.split(/\{\{|\}\}/), 
                    flag = 1
                element.appendChild(document.createElement("p"))
                for(var i = 1, len = all.length; i < all.length; i++) {
                    // 插值表达式
                    if(flag == 1) {
                        flag = 0;
                        (function() {
                            var node = document.createTextNode("");
                            element.appendChild(node);
                            // 视图刷新函数
                            (function(key, node) {
                                node.nodeValue = model[key]
                            })(all[i], node)
                            node = null
                        })()
                    // 普通文本
                    } else {
                        flag = 1
                        var node = document.createTextNode(all[i]);
                        element.appendChild(node);
                    }
                }
            }
            model.name = "nobody"
            model.age = "secret"
            model.country = "**"
            scan(document.getElementById("name"), model)

            function change() {
                var h = this.children[this.selectedIndex].innerHTML.split("-"),
                    dict = ["name", "age", "country"]
                for(var i in dict) {
                    model[dict[i]] = h[i]
                }
            }
        </script>
     </body>
 </html>
w3ctech微信

扫码关注w3ctech微信公众号

共收到1条回复

  • 切换次数多了很卡

    回复此楼