1

backbone | chaplin | coffee tutotial实现

前端MVC框架很多,angular处理DOM的方式比较特别,试用了下感觉不太顺手,backbone
之前学习过一次,由于作者文档写的太烂,遇到各种坑放了一段时间,最近重新学习了
下,组织了下项目结构,分享一下。

js使用coffee,本文由backbone 渐进到chaplin,介绍遇到的坑和学习方法。

此文算我上篇博客现代前端开发小记的姊妹帖

学习路线

首先看backbone, 然后才是chaplin,看官方文档是没有用的,需要读源码

脚手架

本文中用到的代码 chaplin脚手架

此项目可以方便的初始化一个chaplin项目,与gh:paulmillr/brunch-with-chaplin脚手架不
同的是项目文件的组织结构

教程

google backbone + coffee
第一个链接是这个教程

那就根据这个来学习backbone,具体的教程就不细说了。

把项目克隆下来后 git checkout last-backbone
或者如果你不会用git 直接下载release中的last-backbone

具体的依赖安装方式|运行方式请参照master 分支的README.md

项目的文件结构

下图是last-backbone这个commit时的文件结构,现在略有不同,app下每个文件
夹都是一个模块,每个模块都会有assets(写html),initialize(new出各个view),
routes(backbone 路由),views(backbone view), views下有templates(hbs), styles(样式)

common模块放各种基类,和会复用到的东西

app
├── assets
│   ├── images
│   └── index.html
├── common
│   ├── application.coffee
│   ├── config.coffee
│   ├── mediator.coffee
│   ├── mock.coffee
│   ├── models
│   │   └── base
│   │       ├── collection.coffee
│   │       └── model.coffee
│   └── views
│       ├── base
│       │   └── view.coffee
│       └── styles
│           └── application.styl
├── lib
│   ├── utils.coffee
│   └── view-helper.coffee
└── tutorial
    ├── assets
    │   └── README.md
    ├── controllers
    │   └── README.md
    ├── initialize.coffee
    ├── models
    │   ├── item.coffee
    │   └── list.coffee
    ├── routes.coffee
    └── views
        ├── home
        │   ├── item-view.coffee
        │   ├── list-view.coffee
        │   ├── styles
        │   │   └── item.styl
        │   └── templates
        │       └── README.md
        └── README.md

另一个项目 保持更新

skill_issues

backbone相关页面

backbone_issue

backbone的坑

backbone和chaplin最长遇到的问题就是view中没找到具体的DOM,
记住一条金科玉律

el container 选中的DOM必须是在new这个view前已经存在的元素

修改页面的dom使用render

注意,取属性值的时候需要用双引号,因为解释器不识别单引号

$('ul').append "<li>item  #{@counter}</li>"

view el

el必须是**pre exist**,也就是在调用前必须存在此元素

View = require 'common/views/base/view'

module.exports = class ListView extends View

  el: '#test'

  initialize: ->
    _.bindAll @
    @render()

  render: ->
    $(@el).append('<ul><li>hello backbone</li></ul>')
    @

注意<script>require('/tutorial/initialize');</script>这一行需要写在 id='test'
的元素后面,否则会找不到这个dom

<!doctype html>
<!--[if IE 8]>    <html class="no-js lt-ie9" lang="en"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <title>Brunch example application</title>
  <meta name="viewport" content="width=device-width">
  <link rel="stylesheet" href="/stylesheets/app.css">
  <script src="/javascripts/vendor.js"></script>
  <script src="/javascripts/app.js"></script>
</head>
<body>
    <header>
        <h1>title</h1>
        <p>p p p p</p>
    </header>
    <div id="test"></div>
    <script>require('/tutorial/initialize');</script>
</body>
</html>

backbone是没有controllers的,因此chaplin在backbone的基础上加上了controller
以及一些缓存等等

chaplin阶段

git checkout master
或者直接下载最新的代码

使用chaplin后有一些变化,以及用法

view

根据源码
https://github.com/chaplinjs/chaplin/blob/master/src/chaplin/views/view.coffee

  • backbone view中的el现在为container
    constructor: @el = @container if @container

  • autoRender是否在constructor里面调用一次render
    constructor: @render() if @autoRender

不要在使用_bindAll会出现问题

item-view

item-view继承自Chaplin.View,以前使用render添加dom,现在可以直接使用
hbs模板,不过根据源码getTemplateFunction必须重写

* getTemplateFunction ->
    throw new Error 'View#getTemplateFunction must be overridden'

重写成,可以放在你自定义的View基类里面

getTemplateFunction: ->
    @template

hbs模板使用双括号引用model中的属性 {{attr}}

list-view

与item-view相同,也是需要重写getTemplateFunction
list view中的itemView指明具体的ItemView,当list view的collection中
有变化时会自动渲染dom,此例中的addItem在collection里面调用add会处发
这个事件,注意container和listSelector的不同

源码中listSelector的注释:

# as the container of the item views. If you specify `listSelector`, the
# item views will be appended to this element. If empty, $el is used.
listSelector: null

例如本例子中的模板里面有一个ul,注意listSelector是在本模板的dom中选择,
即:

最初
<div id="test">listview会加在这里</div>
加载listview后

<div id="test"><button ...><ul></ul></button></div>
如果listSelector为 'div ul'会选不中这个ul的
使用ul才可以选中

View = require 'common/views/base/view'
CollectionView = require 'common/views/base/collection-view'
List = require 'tutorial/models/list'
Item = require 'tutorial/models/item'
ItemView = require './item-view'

module.exports = class ListView extends CollectionView

  autoRender: true
  container: '#test'
  itemView: ItemView
  listSelector: 'ul'
  template: require './templates/list'

  events:
    'click button': 'addItem'

  initialize: ->
    @collection = new List
    @counter = 0
    super

  addItem: ->
    @counter++
    item = new Item
    item.set
      part2: "#{item.get 'part2'} #{@counter}"
    @collection.add item

模板list.hbs

<button class="pure-button pure-button-primary">Add List Item</button>
<ul></ul>

D咄咄
1.7k 声望257 粉丝

Life is to short, please use python.