Backbone前端框架核心及源码解析

Backbone前端框架核心及源码解析

Backbone是一款前端框架,它的核心是提供了MVC架构中Model(模型)和Collection(集合),以及View(视图)和Router(路由)的基础实现。Backbone的源码易读易懂,阅读源码可以对JavaScript编程有更深刻的理解。

1. Model和Collection

Model

Model表示前端程序中的业务模型。Model对象提供了数据的接口;保存数据,处理数据,触发对View(视图)的更新。在Backbone中,通过继承Backbone.Model来定义一个Model类,通过以下代码实现:

var Book = Backbone.Model.extend({});

在定义了Model类之后,还要定义Model的实例,创建Model实例时可以通过定义默认的数据值:

var Book = Backbone.Model.extend({
  defaults: {
    title: 'unknown',
    author: 'unknown'
  }
});

var book1 = new Book({ title: 'The Lord of the Rings', author: 'J.R.R. Tolkien' });
console.log(book1.get('title')); // "The Lord of the Rings"
console.log(book1.get('author')); // "J.R.R. Tolkien"

Collection

Collection表示一组Model对象。Collection把Model视为一个整体,可以进行Model的批量操作。在Backbone中,通过继承Backbone.Collection来定义一个Collection类,通过以下代码实现:

var Books = Backbone.Collection.extend({
  model: Book
});

在定义了Collection类之后,还要定义Collection的实例,可以通过add()和remove()方法操作Collection对象:

var books = new Books();

var book1 = new Book({ title: 'The Lord of the Rings', author: 'J.R.R. Tolkien' });
var book2 = new Book({ title: 'The Hobbit', author: 'J.R.R. Tolkien' });
var book3 = new Book({ title: 'Harry Potter and the Philosopher\'s Stone', author: 'J.K. Rowling' });

books.add(book1);
books.add(book2);
books.add(book3);

console.log(books.length); // 3

books.remove(book2);
console.log(books.length); // 2

2. View和Router

View

View表示前端程序中的用户界面。View对象接收Model数据,通过模板引擎将数据渲染成html,然后更新到指定的DOM元素上。在Backbone中,通过继承Backbone.View来定义一个View类,通过以下代码实现:

var BookView = Backbone.View.extend({
  tagName: 'div',
  className: 'book-item',
  template: _.template('<h2><%= title %></h2><p><%= author %></p>'),

  initialize: function () {
    this.listenTo(this.model, 'change', this.render);
  },

  render: function () {
    this.$el.html(this.template(this.model.toJSON()));
    return this;
  }
});

在定义了View类之后,还要定义View的实例,通过指定el属性来指定渲染后的html插入到哪个DOM元素内部:

var book1 = new Book({ title: 'The Lord of the Rings', author: 'J.R.R. Tolkien' });
var bookView = new BookView({ model: book1 });
$('#app').append(bookView.el);

Router

Router负责页面的路由控制和处理。Router对象监听URL变化(hashchange事件),响应URL变化,收集路由参数,调用对应的Controller方法。在Backbone中,通过继承Backbone.Router来定义一个Router类,通过以下代码实现:

var AppRouter = Backbone.Router.extend({
  routes: {
    'books/:id': 'showBook'
  },

  showBook: function (id) {
    var book = books.get(id);
    var bookView = new BookView({ model: book });
    $('#app').html(bookView.el);
  }
});

在定义了Router类之后,还要定义Router的实例,启动Backbone的history:

var router = new AppRouter();
Backbone.history.start();

使用hash值#books/123访问页面,Router会捕捉到books/:id的URL,调用对应的showBook方法。showBook方法获取该book的模型数据,使用BookView进行渲染,最后更新到指定的DOM元素上。

3. 示例

示例1:一个简单的待办事项列表

var Todo = Backbone.Model.extend({
  defaults: function () {
    return {
      title: '',
      completed: false
    };
  },

  toggle: function () {
    this.save({
      completed: !this.get('completed')
    });
  }
});

var TodoList = Backbone.Collection.extend({
  model: Todo,

  localStorage: new Backbone.LocalStorage('todos-backbone'),

  completed: function () {
    return this.where({ completed: true });
  },

  remaining: function () {
    return this.where({ completed: false });
  }
});

var Todos = new TodoList();

var TodoView = Backbone.View.extend({
  tagName: 'li',

  template: _.template('<span class="title"><%= title %></span>'),

  events: {
    'click .title': 'toggleCompleted'
  },

  initialize: function () {
    this.listenTo(this.model, 'change', this.render);
  },

  render: function () {
    this.$el.toggleClass('completed', this.model.get('completed'));
    this.$el.html(this.template(this.model.toJSON()));
    return this;
  },

  toggleCompleted: function () {
    this.model.toggle();
  }
});

var AppView = Backbone.View.extend({
  el: '#app',

  statsTemplate: _.template('<span><%= remaining %> items left</span><span><%= completed %> items completed</span>'),

  events: {
    'keypress input': 'addTodo'
  },

  initialize: function () {
    this.$input = this.$('input');
    this.$list = this.$('#todo-list');

    this.listenTo(Todos, 'add', this.addTodoView);
    this.listenTo(Todos, 'reset', this.addAll);
    this.listenTo(Todos, 'change:completed', this.filterOne);
    this.listenTo(Todos, 'filter', this.filterAll);

    Todos.fetch({ reset: true });
  },

  render: function () {
    this.$list.empty();

    Todos.each(function (todo) {
      var view = new TodoView({ model: todo });
      this.$list.append(view.render().el);
    }, this);

    this.renderStats();
  },

  renderStats: function () {
    var completed = Todos.completed().length;
    var remaining = Todos.remaining().length;
    this.$('#todo-stats').html(this.statsTemplate({ completed: completed, remaining: remaining }));
  },

  addTodo: function (e) {
    if (e.keyCode != 13) return;
    if (!this.$input.val().trim()) return;

    Todos.create({ title: this.$input.val().trim() });
    this.$input.val('');
  },

  addTodoView: function (todo) {
    var view = new TodoView({ model: todo });
    this.$list.append(view.render().el);
  },

  addAll: function () {
    Todos.each(this.addTodoView, this);
  },

  filterOne: function (todo) {
    TodoView.hide(todo.get('completed'));
  },

  filterAll: function () {
    Todos.each(this.filterOne, this);
  }
});

var App = new AppView();

在HTML中添加必要的DOM元素:

<body>
  <div id="app">
    <input type="text" placeholder="What need to be done?">
    <span id="todo-stats"></span>
    <ul id="todo-list"></ul>
  </div>
</body>

示例2:简单路由控制

var HomePageView = Backbone.View.extend({
  el: '#app',

  template: _.template('<h1>Backbone Home Page</h1>'),

  render: function () {
    this.$el.html(this.template());
    return this;
  }
});

var AboutPageView = Backbone.View.extend({
  el: '#app',

  template: _.template('<h1>About Us</h1><p>This is the about us page</p>'),

  render: function () {
    this.$el.html(this.template());
    return this;
  }
});

var AppRouter = Backbone.Router.extend({
  routes: {
    '': 'home',
    'about': 'about'
  },

  home: function () {
    var homePageView = new HomePageView();
    homePageView.render();
  },

  about: function () {
    var aboutPageView = new AboutPageView();
    aboutPageView.render();
  }
});

var router = new AppRouter();
Backbone.history.start();

在HTML中添加必要的DOM元素:

<body>
  <div id="app"></div>
  <ul>
    <li><a href="#">Home</a></li>
    <li><a href="#about">About Us</a></li>
  </ul>
</body>

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Backbone前端框架核心及源码解析 - Python技术站

(0)
上一篇 2023年6月11日
下一篇 2023年6月11日

相关文章

  • Ajax 对象 包含post和get两种异步传输方式

    为了详细讲解Ajax对象,我们需要明确以下几个概念: 异步传输:传输数据时不会阻塞页面,用户可以继续进行其他操作。 GET方法:通过URL传输参数,以键值对的形式发到服务端。 POST方法:将参数放在HTTP请求的body中发送到服务端。 Ajax对象是XMLHttpRequest对象的一个实例,可以通过JavaScript代码创建,在实例化完成后使用其op…

    JavaScript 2023年6月11日
    00
  • 原生JS中应该禁止出现的写法

    当使用原生JavaScript编写代码时,需要注意一些写法上的问题,避免引发不必要的错误或者性能问题。以下是几个应该禁止出现的写法。 1. 使用 document.write document.write 是一种在网页中输出HTML的方法,但是它的使用会破坏页面的结构,降低性能,还可能引起安全问题。当使用 document.write 时,浏览器会强制停止所…

    JavaScript 2023年6月10日
    00
  • js闭包实例汇总

    JS闭包实例汇总 在 JavaScript 中,函数是一等公民,它们可以被传递、被赋值、被嵌套定义等等。在函数内定义的函数,被称为闭包(Closure)。闭包可以访问函数外部的变量,而且在函数执行完并返回时,可以保留这些变量的值。 本文将为大家汇总几个 JavaScript 闭包的实例,方便大家加深对闭包的理解。 示例一:计数器 我们可以通过闭包来创建一个计…

    JavaScript 2023年6月10日
    00
  • 关于导入excel时js转换时间的正确方式

    针对“关于导入Excel时JS转换时间的正确方式”的问题,我准备提供以下攻略: 标准日期格式 在Excel中,日期一般使用“yyyy-mm-dd”或“yyyy/mm/dd”的格式表示,如果以文本形式存储的话,在JS中转换日期时会出现错误。因此,在将Excel表格中的日期数据导入时,需要对日期进行预处理,将其按照标准的日期格式进行存储。这里推荐使用xlsx或e…

    JavaScript 2023年5月27日
    00
  • JavaScript中的this妙用实例分析

    讲解JavaScript中的this妙用实例分析的完整攻略如下: 什么是this 在JavaScript中,this是一个特殊的关键字,其用于指向函数运行时的上下文对象。在不同的上下文中,this指向的对象不同,因此this可以有多种用途和应用场景。 this的使用场景 1. 普通函数的调用 当函数被作为普通函数调用时,this指向window对象(全局对象…

    JavaScript 2023年5月28日
    00
  • react-router-dom v6 使用详细示例

    这里给出使用 React-Router-Dom 版本 6.x 的详细攻略,包含基本概念、用法介绍、代码示例等,方便大家快速上手。 基本概念 React-Router-Dom 是一个 React 的声明式路由库,在 React 应用中使用路由的时候非常方便。在使用 React-Router-Dom 时,主要涉及到以下几个核心概念: Router:定义路由的容器…

    JavaScript 2023年6月11日
    00
  • javascript导出csv文件(excel)的方法示例

    下面是关于“javascript导出csv文件(excel)的方法示例”的完整攻略: 一、CSV文件格式介绍 CSV(Comma-Separated Values)就是指逗号分隔符,通常是一种保存矩阵数据的文件格式。每行记录表示一行,以逗号作为分隔符,不同列数据存在不同位置,可以通过表格对齐的方式方便地分辨出来。 例如:下面是一个CSV文件的模板: 姓名,学…

    JavaScript 2023年5月27日
    00
  • 浅析JS中常用类型转换及运算符表达式

    浅析JS中常用类型转换及运算符表达式 类型转换 显式类型转换 字符串转换 使用toString()、String()函数将其他类型转为字符串类型,或使用+运算符将其他类型与字符串拼接即可: var num1 = 123; console.log(num1.toString()); // "123" console.log(String(n…

    JavaScript 2023年5月28日
    00
合作推广
合作推广
分享本页
返回顶部