• Backbone实例todos分析


    源码来自:http://todomvc.com/examples/backbone/

    这是一个用Backbone.js完成的待办事项实例,精简但完善,可以帮助很好的帮助理解Backbone的API,MVC框架和写webApp的基本思路。

    下面让我们一步步分析,

    准备工作:

    首先是html页面,新建index.html,并保存以下代码:

    <!doctype html>
    <html lang="en" data-framework="backbonejs">
        <head>
            <meta charset="utf-8">
            <title>Backbone.js • TodoMVC</title>
            <link rel="stylesheet" href="bower_components/todomvc-common/base.css">
        </head>
        <body>
            <section id="todoapp">
                <header id="header">
                    <h1>todos</h1>
                    <input id="new-todo" placeholder="What needs to be done?" autofocus>
                </header>
                <section id="main">
                    <input id="toggle-all" type="checkbox">
                    <label for="toggle-all">Mark all as complete</label>
                    <ul id="todo-list"></ul>
                </section>
                <footer id="footer"></footer>
            </section>
            <footer id="info">
                <p>Double-click to edit a todo</p>
                <p>Written by <a href="https://github.com/addyosmani">Addy Osmani</a></p>
                <p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
            </footer>
            <!-- Templates -->
            <script type="text/template" id="item-template">
                <div class="view">
                    <input class="toggle" type="checkbox" <%= completed ? 'checked' : '' %>>
                    <label><%- title %></label>
                    <button class="destroy"></button>
                </div>
                <input class="edit" value="<%- title %>">
            </script>
            <script type="text/template" id="stats-template">
                <span id="todo-count"><strong><%= remaining %></strong> <%= remaining === 1 ? 'item' : 'items' %> left</span>
                <ul id="filters">
                    <li>
                        <a class="selected" href="#/">All</a>
                    </li>
                    <li>
                        <a href="#/active">Active</a>
                    </li>
                    <li>
                        <a href="#/completed">Completed</a>
                    </li>
                </ul>
                <% if (completed) { %>
                <button id="clear-completed">Clear completed (<%= completed %>)</button>
                <% } %>
            </script>
            <script src="bower_components/jquery/jquery.js"></script>
            <script src="bower_components/underscore/underscore.js"></script>
            <script src="bower_components/backbone/backbone.js"></script>
            <script src="bower_components/backbone.localStorage/backbone.localStorage.js"></script>
            <script src="js/models/todo.js"></script>
            <script src="js/collections/todos.js"></script>
            <script src="js/views/todo-view.js"></script>
            <script src="js/views/app-view.js"></script>
            <script src="js/routers/router.js"></script>
            <script src="js/app.js"></script>
        </body>
    </html>
    View Code

    这是webapp的主页面,它引入的文件有样式表base.css;js框架jquery.js,underscore.js,backbone.js,backbone.localStorage.js,请大家自行引入。然后是即将利用backbone编写的js代码.为了方便理解,原作者将这些JS代码分成了5个JS文件,我们将深入分析。

    先简单介绍一下这些js框架和我们页面的关系:

    1.jquery.js:我们将利用jquery操作dom,

    2.underscore.js:backbone的依赖库,提供一下方便的方法,和模板的操作。

    3.backbone.js:我们主要使用的MVC框架

    4.backbone.localStorage.js:backbone的拓展库,用来操作HTML5新加入的本地存储

    页面的样式表base.css

    html,
    body {
        margin: 0;
        padding: 0;
    }
    
    button {
        margin: 0;
        padding: 0;
        border: 0;
        background: none;
        font-size: 100%;
        vertical-align: baseline;
        font-family: inherit;
        color: inherit;
        -webkit-appearance: none;
        -ms-appearance: none;
        -o-appearance: none;
        appearance: none;
    }
    
    body {
        font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
        line-height: 1.4em;
        background: #eaeaea url('bg.png');
        color: #4d4d4d;
        width: 550px;
        margin: 0 auto;
        -webkit-font-smoothing: antialiased;
        -moz-font-smoothing: antialiased;
        -ms-font-smoothing: antialiased;
        -o-font-smoothing: antialiased;
        font-smoothing: antialiased;
    }
    
    button,
    input[type="checkbox"] {
      outline: none;
    }
    
    #todoapp {
        background: #fff;
        background: rgba(255, 255, 255, 0.9);
        margin: 130px 0 40px 0;
        border: 1px solid #ccc;
        position: relative;
        border-top-left-radius: 2px;
        border-top-right-radius: 2px;
        box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.2),
                    0 25px 50px 0 rgba(0, 0, 0, 0.15);
    }
    
    #todoapp:before {
        content: '';
        border-left: 1px solid #f5d6d6;
        border-right: 1px solid #f5d6d6;
        width: 2px;
        position: absolute;
        top: 0;
        left: 40px;
        height: 100%;
    }
    
    #todoapp input::-webkit-input-placeholder {
        font-style: italic;
    }
    
    #todoapp input::-moz-placeholder {
        font-style: italic;
        color: #a9a9a9;
    }
    
    #todoapp h1 {
        position: absolute;
        top: -120px;
        width: 100%;
        font-size: 70px;
        font-weight: bold;
        text-align: center;
        color: #b3b3b3;
        color: rgba(255, 255, 255, 0.3);
        text-shadow: -1px -1px rgba(0, 0, 0, 0.2);
        -webkit-text-rendering: optimizeLegibility;
        -moz-text-rendering: optimizeLegibility;
        -ms-text-rendering: optimizeLegibility;
        -o-text-rendering: optimizeLegibility;
        text-rendering: optimizeLegibility;
    }
    
    #header {
        padding-top: 15px;
        border-radius: inherit;
    }
    
    #header:before {
        content: '';
        position: absolute;
        top: 0;
        right: 0;
        left: 0;
        height: 15px;
        z-index: 2;
        border-bottom: 1px solid #6c615c;
        background: #8d7d77;
        background: -webkit-gradient(linear, left top, left bottom, from(rgba(132, 110, 100, 0.8)),to(rgba(101, 84, 76, 0.8)));
        background: -webkit-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
        background: linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
        filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670');
        border-top-left-radius: 1px;
        border-top-right-radius: 1px;
    }
    
    #new-todo,
    .edit {
        position: relative;
        margin: 0;
        width: 100%;
        font-size: 24px;
        font-family: inherit;
        line-height: 1.4em;
        border: 0;
        outline: none;
        color: inherit;
        padding: 6px;
        border: 1px solid #999;
        box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
        -moz-box-sizing: border-box;
        -ms-box-sizing: border-box;
        -o-box-sizing: border-box;
        box-sizing: border-box;
        -webkit-font-smoothing: antialiased;
        -moz-font-smoothing: antialiased;
        -ms-font-smoothing: antialiased;
        -o-font-smoothing: antialiased;
        font-smoothing: antialiased;
    }
    
    #new-todo {
        padding: 16px 16px 16px 60px;
        border: none;
        background: rgba(0, 0, 0, 0.02);
        z-index: 2;
        box-shadow: none;
    }
    
    #main {
        position: relative;
        z-index: 2;
        border-top: 1px dotted #adadad;
    }
    
    label[for='toggle-all'] {
        display: none;
    }
    
    #toggle-all {
        position: absolute;
        top: -42px;
        left: -4px;
        width: 40px;
        text-align: center;
        /* Mobile Safari */
        border: none;
    }
    
    #toggle-all:before {
        content: '»';
        font-size: 28px;
        color: #d9d9d9;
        padding: 0 25px 7px;
    }
    
    #toggle-all:checked:before {
        color: #737373;
    }
    
    #todo-list {
        margin: 0;
        padding: 0;
        list-style: none;
    }
    
    #todo-list li {
        position: relative;
        font-size: 24px;
        border-bottom: 1px dotted #ccc;
    }
    
    #todo-list li:last-child {
        border-bottom: none;
    }
    
    #todo-list li.editing {
        border-bottom: none;
        padding: 0;
    }
    
    #todo-list li.editing .edit {
        display: block;
        width: 506px;
        padding: 13px 17px 12px 17px;
        margin: 0 0 0 43px;
    }
    
    #todo-list li.editing .view {
        display: none;
    }
    
    #todo-list li .toggle {
        text-align: center;
        width: 40px;
        /* auto, since non-WebKit browsers doesn't support input styling */
        height: auto;
        position: absolute;
        top: 0;
        bottom: 0;
        margin: auto 0;
        /* Mobile Safari */
        border: none;
        -webkit-appearance: none;
        -ms-appearance: none;
        -o-appearance: none;
        appearance: none;
    }
    
    #todo-list li .toggle:after {
        content: '✔';
        /* 40 + a couple of pixels visual adjustment */
        line-height: 43px;
        font-size: 20px;
        color: #d9d9d9;
        text-shadow: 0 -1px 0 #bfbfbf;
    }
    
    #todo-list li .toggle:checked:after {
        color: #85ada7;
        text-shadow: 0 1px 0 #669991;
        bottom: 1px;
        position: relative;
    }
    
    #todo-list li label {
        white-space: pre;
        word-break: break-word;
        padding: 15px 60px 15px 15px;
        margin-left: 45px;
        display: block;
        line-height: 1.2;
        -webkit-transition: color 0.4s;
        transition: color 0.4s;
    }
    
    #todo-list li.completed label {
        color: #a9a9a9;
        text-decoration: line-through;
    }
    
    #todo-list li .destroy {
        display: none;
        position: absolute;
        top: 0;
        right: 10px;
        bottom: 0;
        width: 40px;
        height: 40px;
        margin: auto 0;
        font-size: 22px;
        color: #a88a8a;
        -webkit-transition: all 0.2s;
        transition: all 0.2s;
    }
    
    #todo-list li .destroy:hover {
        text-shadow: 0 0 1px #000,
                     0 0 10px rgba(199, 107, 107, 0.8);
        -webkit-transform: scale(1.3);
        transform: scale(1.3);
    }
    
    #todo-list li .destroy:after {
        content: '✖';
    }
    
    #todo-list li:hover .destroy {
        display: block;
    }
    
    #todo-list li .edit {
        display: none;
    }
    
    #todo-list li.editing:last-child {
        margin-bottom: -1px;
    }
    
    #footer {
        color: #777;
        padding: 0 15px;
        position: absolute;
        right: 0;
        bottom: -31px;
        left: 0;
        height: 20px;
        z-index: 1;
        text-align: center;
    }
    
    #footer:before {
        content: '';
        position: absolute;
        right: 0;
        bottom: 31px;
        left: 0;
        height: 50px;
        z-index: -1;
        box-shadow: 0 1px 1px rgba(0, 0, 0, 0.3),
                    0 6px 0 -3px rgba(255, 255, 255, 0.8),
                    0 7px 1px -3px rgba(0, 0, 0, 0.3),
                    0 43px 0 -6px rgba(255, 255, 255, 0.8),
                    0 44px 2px -6px rgba(0, 0, 0, 0.2);
    }
    
    #todo-count {
        float: left;
        text-align: left;
    }
    
    #filters {
        margin: 0;
        padding: 0;
        list-style: none;
        position: absolute;
        right: 0;
        left: 0;
    }
    
    #filters li {
        display: inline;
    }
    
    #filters li a {
        color: #83756f;
        margin: 2px;
        text-decoration: none;
    }
    
    #filters li a.selected {
        font-weight: bold;
    }
    
    #clear-completed {
        float: right;
        position: relative;
        line-height: 20px;
        text-decoration: none;
        background: rgba(0, 0, 0, 0.1);
        font-size: 11px;
        padding: 0 10px;
        border-radius: 3px;
        box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.2);
    }
    
    #clear-completed:hover {
        background: rgba(0, 0, 0, 0.15);
        box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.3);
    }
    
    #info {
        margin: 65px auto 0;
        color: #a6a6a6;
        font-size: 12px;
        text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7);
        text-align: center;
    }
    
    #info a {
        color: inherit;
    }
    
    /*
        Hack to remove background from Mobile Safari.
        Can't use it globally since it destroys checkboxes in Firefox and Opera
    */
    
    @media screen and (-webkit-min-device-pixel-ratio:0) {
        #toggle-all,
        #todo-list li .toggle {
            background: none;
        }
    
        #todo-list li .toggle {
            height: 40px;
        }
    
        #toggle-all {
            top: -56px;
            left: -15px;
            width: 65px;
            height: 41px;
            -webkit-transform: rotate(90deg);
            transform: rotate(90deg);
            -webkit-appearance: none;
            appearance: none;
        }
    }
    
    .hidden {
        display: none;
    }
    
    hr {
        margin: 20px 0;
        border: 0;
        border-top: 1px dashed #C5C5C5;
        border-bottom: 1px dashed #F7F7F7;
    }
    
    .learn a {
        font-weight: normal;
        text-decoration: none;
        color: #b83f45;
    }
    
    .learn a:hover {
        text-decoration: underline;
        color: #787e7e;
    }
    
    .learn h3,
    .learn h4,
    .learn h5 {
        margin: 10px 0;
        font-weight: 500;
        line-height: 1.2;
        color: #000;
    }
    
    .learn h3 {
        font-size: 24px;
    }
    
    .learn h4 {
        font-size: 18px;
    }
    
    .learn h5 {
        margin-bottom: 0;
        font-size: 14px;
    }
    
    .learn ul {
        padding: 0;
        margin: 0 0 30px 25px;
    }
    
    .learn li {
        line-height: 20px;
    }
    
    .learn p {
        font-size: 15px;
        font-weight: 300;
        line-height: 1.3;
        margin-top: 0;
        margin-bottom: 0;
    }
    
    .quote {
        border: none;
        margin: 20px 0 60px 0;
    }
    
    .quote p {
        font-style: italic;
    }
    
    .quote p:before {
        content: '“';
        font-size: 50px;
        opacity: .15;
        position: absolute;
        top: -20px;
        left: 3px;
    }
    
    .quote p:after {
        content: '”';
        font-size: 50px;
        opacity: .15;
        position: absolute;
        bottom: -42px;
        right: 3px;
    }
    
    .quote footer {
        position: absolute;
        bottom: -40px;
        right: 0;
    }
    
    .quote footer img {
        border-radius: 3px;
    }
    
    .quote footer a {
        margin-left: 5px;
        vertical-align: middle;
    }
    
    .speech-bubble {
        position: relative;
        padding: 10px;
        background: rgba(0, 0, 0, .04);
        border-radius: 5px;
    }
    
    .speech-bubble:after {
        content: '';
        position: absolute;
        top: 100%;
        right: 30px;
        border: 13px solid transparent;
        border-top-color: rgba(0, 0, 0, .04);
    }
    
    .learn-bar > .learn {
        position: absolute;
        width: 272px;
        top: 8px;
        left: -300px;
        padding: 10px;
        border-radius: 5px;
        background-color: rgba(255, 255, 255, .6);
        -webkit-transition-property: left;
        transition-property: left;
        -webkit-transition-duration: 500ms;
        transition-duration: 500ms;
    }
    
    @media (min- 899px) {
        .learn-bar {
            width: auto;
            margin: 0 0 0 300px;
        }
    
        .learn-bar > .learn {
            left: 8px;
        }
    
        .learn-bar #todoapp {
            width: 550px;
            margin: 130px auto 40px auto;
        }
    }
    View Code

    代码分析:

    todo.js

    //app对象
    var app = app || {};
    
    (function () {
        'use strict';
    
        // Todo 模型
        // ----------
    
        
        //我们基本的Todo模型有`title`,`order`,`completed`,属性
        app.Todo = Backbone.Model.extend({
            //todo默认属性,确保每个对象都拥有`title` and `completed`.
            defaults: {
                title: '',
                completed: false
            },
    
            //改变todo中`completed`属性为反向状态 
            toggle: function () {
                this.save({
                    completed: !this.get('completed')
                });
            }
        });
    })();

    在todo app我们实现要实现的功能中,一个基本待办事项就是最基本的数据模型,它拥有title,completed,order,三个属性,分别表示显示的标题,是否完成和顺序,其中title,completed为默认属性。

    模型有一个改变状态的方法。save方法除了将数据保存到模型中,还将向服务器发送request请求,如果成功,触发sync事件。简言之,与数据存储方面配合,利用save不单是将数据存储到我们定义的模型里,还将保存到服务器上。

    todos.js

    //app对象
    var app = app || {};
    
    (function () {
        'use strict';
    
        // Todo 集合
        // ---------------
    
        // 这里数据集合将存储到本地存储,替代服务器存储
        var Todos = Backbone.Collection.extend({
            //引用这个集合的模型 
            model: app.Todo,
    
            // 集合中所有的todo 模型都将存在本地
            localStorage: new Backbone.LocalStorage('todos-backbone'),
    
            // 过滤为所有完成的todo模型
            completed: function () {
                return this.where({completed: true});
            },
    
            // 过滤为所有为完成的todo模型
            remaining: function () {
                return this.where({completed: false});
            },
    
            // 我们将保持Todos有序,不管是不是被无序存储
            // 生成下个todo模型的顺序ID
            nextOrder: function () {
                return this.length ? this.last().get('order') + 1 : 1;
            },
    
            // 所有的todo将以最初插入的顺序保存到Todos当中。
            comparator: 'order'
        });
    
        // 创建一个todos集合。
        app.todos = new Todos();
    })();

    这是数据模型的集合。

    todo-view.js

    var app = app || {};
    
    (function ($) {
        'use strict';
    
        // todo 单个模型的视图
        // --------------
    
        // 一个todo模型的DOM元素
        app.TodoView = Backbone.View.extend({
            // 整个视图在一个li标签中
            tagName:  'li',
    
            // 缓存单个模型的模板函数
            template: _.template($('#item-template').html()),
    
            // 定义单个模型页面视图中指定DOM元素触发事件时调用的函数
            events: {
                'click .toggle': 'toggleCompleted',
                'dblclick label': 'edit',
                'click .destroy': 'clear',
                'keypress .edit': 'updateOnEnter',
                'keydown .edit': 'revertOnEscape',
                'blur .edit': 'close'
            },
    
            // 监听其对应模型的事件,这是一对一的,这个视图,监听其模型。
            initialize: function () {
                this.listenTo(this.model, 'change', this.render);
                this.listenTo(this.model, 'destroy', this.remove);
                this.listenTo(this.model, 'visible', this.toggleVisible);
            },
    
            // 生成模型的标题。
            render: function () {
                //Backbone LocalStorage保存模型时,会增加一个ID属性,这将引起render事件再次发生。我们想过滤由此引起的第二次render,因此增加了一段功能。
                // 这是localStorage.js的一个BUG,相关信息可以查看 https://github.com/tastejs/todomvc/issues/469
                if (this.model.changed.id !== undefined) {
                    return;
                }
    
                this.$el.html(this.template(this.model.toJSON()));
                this.$el.toggleClass('completed', this.model.get('completed'));
                this.toggleVisible();
                this.$input = this.$('.edit');
                return this;
            },
    
            toggleVisible: function () {
                this.$el.toggleClass('hidden', this.isHidden());
            },
    
            isHidden: function () {
                return this.model.get('completed') ?
                    app.TodoFilter === 'active' :
                    app.TodoFilter === 'completed';
            },
    
            // 改变模型completed状态
            toggleCompleted: function () {
                this.model.toggle();
            },
    
            // 转到编辑状态
            edit: function () {
                this.$el.addClass('editing');
                this.$input.focus();
            },
    
            // 关闭编辑模式,存储对模型的改变
            close: function () {
                var value = this.$input.val();
                var trimmedValue = value.trim();
    
                // 在非编辑状态下直接返回
                if (!this.$el.hasClass('editing')) {
                    return;
                }
    
                if (trimmedValue) {
                    this.model.save({ title: trimmedValue });
    
                    if (value !== trimmedValue) {
                        // 只增加了两边的空格的更改并不会存入服务器中,在此情况下,我们重新渲染视图,
                        // 达到显示和后台统一的目的。
                        this.model.trigger('change');
                    }
                } else {
                    this.clear();
                }
    
                this.$el.removeClass('editing');
            },
    
            // 如果你按下回车键,将跳到编辑状态
            updateOnEnter: function (e) {
                if (e.which === ENTER_KEY) {
                    this.close();
                }
            },
    
            // 如果你按下esc键,将恢复视图为模型的数据,并离开编辑状态
            revertOnEscape: function (e) {
                if (e.which === ESC_KEY) {
                    this.$el.removeClass('editing');
                    // 重置输入框为模型中的数据
                    this.$input.val(this.model.get('title'));
                }
            },
    
            // 删除条目,并从localStorage中销毁,并删除视图(事件监听destroy)
            clear: function () {
                this.model.destroy();
            }
        });
    })(jQuery);

     这里是单个条目的视图,它主要负责对单个条目的操作,如删除,更改等每个条目都有的功能。

    app-view.js

    var app = app || {};
    
    (function ($) {
        'use strict';
    
        // 程序
        // ---------------
    
        // 整体的程序视图
        app.AppView = Backbone.View.extend({
    
            // 视图绑定为已经存在的页面节点
            el: '#todoapp',
    
            // 缓存状态模板
            statsTemplate: _.template($('#stats-template').html()),
    
            events: {
                'keypress #new-todo': 'createOnEnter',
                'click #clear-completed': 'clearCompleted',
                'click #toggle-all': 'toggleAllComplete'
            },
    
            // 在初始化时,我们绑定相关的事件到集合实例上,
            // 重置时,重新添加所有模型。
            initialize: function () {
                this.allCheckbox = this.$('#toggle-all')[0];
                this.$input = this.$('#new-todo');
                this.$footer = this.$('#footer');
                this.$main = this.$('#main');
                this.$list = $('#todo-list');
    
                this.listenTo(app.todos, 'add', this.addOne);
                this.listenTo(app.todos, 'reset', this.addAll);
                this.listenTo(app.todos, 'change:completed', this.filterOne);
                this.listenTo(app.todos, 'filter', this.filterAll);
                this.listenTo(app.todos, 'all', this.render);
    
                // 抑制由于每个add事件引起的视图生成。从本地存储获取到模型时,触发reset事件,添加所有的模型到集合中。
                app.todos.fetch({reset: true});
            },
    
            // reset并不会引起视图的生成。
            render: function () {
                var completed = app.todos.completed().length;
                var remaining = app.todos.remaining().length;
    
                if (app.todos.length) {
                    this.$main.show();
                    this.$footer.show();
    
                    this.$footer.html(this.statsTemplate({
                        completed: completed,
                        remaining: remaining
                    }));
    
                    this.$('#filters li a')
                        .removeClass('selected')
                        .filter('[href="#/' + (app.TodoFilter || '') + '"]')
                        .addClass('selected');
                } else {
                    this.$main.hide();
                    this.$footer.hide();
                }
    
                this.allCheckbox.checked = !remaining;
            },
    
            // 为新增的模型创建视图,添加到页面中去
            addOne: function (todo) {
                var view = new app.TodoView({ model: todo });
                this.$list.append(view.render().el);
            },
    
            // 一次添加所有模型视图
            addAll: function () {
                this.$list.html('');
                app.todos.each(this.addOne, this);
            },
    
            filterOne: function (todo) {
                todo.trigger('visible');
            },
    
            filterAll: function () {
                app.todos.each(this.filterOne, this);
            },
    
            // 生成新模型的属性
            newAttributes: function () {
                return {
                    title: this.$input.val().trim(),
                    order: app.todos.nextOrder(),
                    completed: false
                };
            },
    
            // 回车键保存模型,且保存到localStorage
            createOnEnter: function (e) {
                if (e.which === ENTER_KEY && this.$input.val().trim()) {
                    app.todos.create(this.newAttributes());
                    this.$input.val('');
                }
            },
    
            // 清除所有完成的模型,
            clearCompleted: function () {
                _.invoke(app.todos.completed(), 'destroy');
                return false;
            },
    
            toggleAllComplete: function () {
                var completed = this.allCheckbox.checked;
    
                app.todos.each(function (todo) {
                    todo.save({
                        completed: completed
                    });
                });
            }
        });
    })(jQuery);

    主视图,主程序,前面所有的模型,集合,视图,都由他来管理。渲染整个视图,监听新增事件,添加条目到集合中等全面的问题处理。

    route.js

    var app = app || {};
    
    (function () {
        'use strict';
    
        // Todo 路由
        // ----------
        var TodoRouter = Backbone.Router.extend({
            routes: {
                '*filter': 'setFilter'
            },
    
            setFilter: function (param) {
                // 存储目前的过滤参数。
                app.TodoFilter = param || '';
    
                // 触发过滤事件,改变视图的隐藏显示。
                app.todos.trigger('filter');
            }
        });
    
        app.TodoRouter = new TodoRouter();
        Backbone.history.start();
    })();

    利用route,保存参数到变量中,供程序使用

    app.js

    var app = app || {};
    var ENTER_KEY = 13;
    var ESC_KEY = 27;
    
    $(function () {
        'use strict';
    
        // 创建App实例,初始化所有功能
        new app.AppView();
    });

    初始化真个程序。

  • 相关阅读:
    Redis之分布式锁的使用
    Redis之lua脚本
    Redis 集群的水平扩缩容
    Redis集群搭建及原理
    Redis 的主从、哨兵架构
    CompletableFuture 使用介绍
    Spring Boot 2.x使用H2数据
    pom.xml
    nexus-staging-maven-plugin 踩坑
    安卓Hook折腾研究的笔记记录
  • 原文地址:https://www.cnblogs.com/winderby/p/4111425.html
Copyright © 2020-2023  润新知