用avalon實現一個完整的todomvc(帶router)

呂大豹發表於2015-02-05

  照著todomvc官網的例子,做了一個avalon版的todos,功能全都有了,而且加了router模組,比司徒大大寫的都完善(≧▽≦)/~

  js檔案整整100行,初次使用avalon,書寫過程中繞了一些彎子,不過還好最終繞回來了。整體感覺如下:

  1. 相比用jQuery,程式碼量下去了,編碼消耗的時間貌似更多了,一來是viewmodel需要一定的邏輯設計,不是像用jQuery那樣一根筋一碼到底,二來是可能我對框架還不是很熟,以後熟悉後效率會飛速提升。
  2. 有一些特性並不是想當然的那樣,比如對陣列監控,目前只能監控length的變化,陣列元素如果是物件,屬性發生變化無法監控。不過可以通過其他方式變通實現。
  3. view層能看到什麼,vm層幾乎都需要有一個屬性與之對應,寧可多寫一個屬性,也不要繞別的邏輯來展示資料了。vm扁平化應該是設計思路。

  demo展示如下:

  

  你也可以點這裡訪問單獨頁面。

  原始碼也貼一下好了:

  html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf8" />
    <title>avalon todos</title>
    <link rel="stylesheet" href="css/base.css">
    <script src="js/avalon.min.js"></script>
</head>
<body>
<section id="todoapp" ms-controller="todos">
    <header id="header">
        <h1>todos</h1>
        <input id="new-todo" placeholder="What needs to be done?" autofocus ms-duplex="newtodo" ms-keyup="add">
    </header>
    <section id="main" style="display: block;">
        <input id="toggle-all" type="checkbox" ms-duplex-checked="allchecked">
        <label for="toggle-all">Mark all as complete</label>
        <ul id="todo-list">
            <li ms-class="completed:el.complete" ms-class-1="editing: $index === editindex" ms-repeat="todolist" ms-visible="filter===1 || filter===el.complete">
                <div class="view">
                    <input class="toggle" type="checkbox" ms-duplex-checked="el.complete" ms-change="setcompletednum">
                    <label ms-dblclick="edit($index, this)">{{el.content}}</label>
                    <button class="destroy" ms-click="$remove"></button>
                </div>
                <input class="edit" ms-duplex="el.content" ms-blur="editover">
            </li>
        </ul>
    </section>
    <footer id="footer" style="display: block;">
        <span id="todo-count"><strong>{{todolist.length}}</strong> item left</span>
        <ul id="filters">
            <li>
                <a ms-class="selected:filter===1" href="#!/all" ms-click="setFilter(1)">All</a>
            </li>
            <li>
                <a ms-class="selected:filter===false" href="#!/active" ms-click="setFilter(false)">Active</a>
            </li>
            <li>
                <a ms-class="selected:filter===true" href="#!/completed" ms-click="setFilter(true)">Completed</a>
            </li>
        </ul>
        <button id="clear-completed" ms-click="clear">Clear completed ({{completednum}})</button>
    </footer>
</section>
<div id="info">
    <p>雙擊列表可編輯</p>
    <p>前進、後退可觀察路由效果</p>
    <p>Created by <a href="http://www.cnblogs.com/lvdabao">呂大豹</a></p>
</div>


<script src="js/index.js"></script>
</body>
</html>

  index.js:

require(["mmRouter"], function(){
    var model = avalon.define({
        $id: "todos",
        newtodo: "",
        filter: 1, //1:all, false:active, true:completed
        allchecked: false,
        editindex: -1, //當前正在編輯的索引
        todolist: [
            {
                content: 'test111',
                complete: false
            },
            {
                content: 'test222',
                complete: true
            }
        ],
        completednum: 0,
        setcompletednum: function(){
            setTimeout(function(){
                var count = 0;
                avalon.each(model.todolist, function(i, el){
                    if(el.complete){
                        count++;
                    }
                });
                model.completednum = count;    
            }, 0);
        },
        add: function(e) {
            if(e.keyCode === 13){
                var newtodo = model.newtodo.trim();
                if (!newtodo.length) {
                    return;
                }
                model.todolist.push({
                    content: newtodo,
                    complete: false
                });
                model.newtodo = "";
            }
        },
        edit: function($index, node){
            model.editindex = $index;
            node.parentNode.parentNode.getElementsByTagName('input')[1].focus();
        },
        editover: function(){
            model.editindex = -1;
        },
        clear : function(){
            var actived = [];
            avalon.each(model.todolist, function(i, el){
                if(!el.complete){
                    actived.push(el);
                }
            });
            model.todolist = actived;
            model.completednum = 0;
        },
        setFilter: function(value){
            model.filter = value;
        }

    });
    model.setcompletednum();
    model.$watch('allchecked', function(a, b){
        avalon.each(model.todolist, function(i, el){
            el.complete = a;
        });
        if(a){
            model.completednum = model.todolist.length;
        }
        else{
            model.completednum = 0;
        }
    });
    model.todolist.$watch('length', function(){
        model.setcompletednum();
    });
    function callback() {
        var filter = 1;
        switch(this.path){
            case '\/active' :
                filter = false;
            break;
            case '\/completed' :
                filter = true;
            break
            case '\/all' :
                filter = 1;
            break;
        }
        model.setFilter(filter);
    }
    avalon.router.get("/all", callback)
    avalon.router.get("/active", callback)
    avalon.router.get("/completed", callback)
    avalon.history.start();
    avalon.scan();
});

 

相關文章