Freewind @ Thoughtworks scala java javascript dart 工具 编程实践 月结 math python english [comments admin] [feed]

(2011-10-20) backbone.js

广告: 云梯:翻墙vpn (省10元) 土行孙:科研用户翻墙http proxy (有优惠)

backbone.js是一个javascript库。当我们需要在页面中写大量的javascript代码来处理页面逻辑时,backbone非常有用,因为它的设计目的就是把javascript代码分解为不同的层来让代码更加清晰。

网址:http://documentcloud.github.com/backbone/

名字backbone中文是"脊椎”,可以想到它的定位:就像脊椎骨一样撑起整个程序的结构,其它的javascript代码,都是附着在它上面的血肉。

在backbone里,有这样几个概念:Model, View, Router, Collection, Events。没错,它有MVC结构。

Model就像是javabean,它对应的是数据。View对应的是页面上的某一个组件,可以增加各种改变页面效果的方法。Router可用来将页面上的链接(准确的说,是用不同的锚点来代替可跳转的链接)与某些方法联系起来。Collection是一些Model的集全,它比Model多一些事件。Event用来表明发生了什么操作。

刘松利用backbone.js和coffeescript写了一个简单的程序,是一个简单的聊天室程序的页面。我先把它们的代码贴在这里。

main.html



<title></title>      
<style>      
        /** reset **/      
    body {      
        font-size: 14px;      
    } 

    body, ul, li, div, h3 {     
        padding: 0;      
        margin: 0;      
    } 

    ul {     
        list-style: none;      
    } 

        /** layout **/     
    .main {      
        display: box;      
        box-orient: horizonal; 

        display: -moz-box;     
        -moz-box-orient: horizonal;      
        display: -webkit-box;      
        -webkit-box-orient: horizonal; 

        width: 100%;     
    } 

    .content {     
        box-flex: 1; 

        -moz-box-flex: 1;     
        -webkit-box-flex: 1;      
    } 

        /** header **/     
    .header {      
        background-image: linear-gradient(top, #6381B8, #264175);      
        background-image: -moz-linear-gradient(top, #6381B8, #264175);      
        background-image: -webkit-linear-gradient(top, #6381B8, #264175); 

        box-shadow: 0 1px 0 #809DD4 inset, 0 -1px 0 #000000 inset;     
        height: 40px;      
    } 

        /** sidebar **/     
    .sidebar {      
        height: 600px;      
        width: 200px;      
        background-color: #DFE6EE;      
        border-right: 1px solid #B4BBC4;      
    } 

    .sidebar h3 {     
        background-image: linear-gradient(top, #EDF3FA, #D0D9E4);      
        background-image: -moz-linear-gradient(center top, #EDF3FA, #D0D9E4);      
        background-image: -webkit-linear-gradient(top, #EDF3FA, #D0D9E4); 

        border-top: 1px solid #FFFFFF;     
        border-bottom: 1px solid #B4BBC4;      
        color: #747D84;      
        text-shadow: 0 1px 0 #FFFFFF;      
        font-size: 14px;      
        line-height: 20px;      
        font-weight: bold;      
        text-indent: 10px;      
    } 

    .sidebar ul li a {     
        box-shadow: 0 1px 0 #EEF6FF inset, 0 -1px 0 #D3D9E1 inset;      
        display: block;      
        line-height: 26px;      
        padding-left: 6px;      
        text-decoration: none;      
        color: #000;      
        cursor: pointer;      
        font-size: 12px;      
        /*-webkit-transition:All 0.1s ease;*/      
        /*-moz-transition:All 0.1s ease;*/      
        border-left: 3px solid transparent;;      
    } 

    .sidebar ul li a:hover {     
        border-left: 3px solid #748DBB;      
    } 

    .sidebar ul li.active a {     
        background-color: #748DBB;      
        background-image: linear-gradient(center top, #ADBDD7 0pt, #748DBB 100%);      
        background-image: -moz-linear-gradient(center top, #ADBDD7 0pt, #748DBB 100%);      
        background-image: -webkit-linear-gradient(top, #ADBDD7 0pt, #748DBB 100%);      
        box-shadow: 0 1px 0 #899CC0 inset, 0 2px 0 #B4C6E4 inset, 0 -1px 0 #6C7B98 inset;      
        margin: -1px 0 0;      
        text-shadow: 0 1px 1px #474E59;      
        font-weight: bold;      
        display: block;      
        line-height: 30px;      
        color: #FFFFFF;      
    } 

        /** content **/     
    .content {      
        color: #444444;      
    } 

    .content > h3 {     
        background: linear-gradient(center top, #F3F3F3, #D7D7D7) repeat scroll 0 0 #E7E7E7;      
        background: -moz-linear-gradient(center top, #F3F3F3, #D7D7D7) repeat scroll 0 0 #E7E7E7;      
        background: -webkit-linear-gradient(top, #F3F3F3, #D7D7D7) repeat scroll 0 0 #E7E7E7;      
        border-bottom: 1px solid #B7B7B7;      
        border-top: 1px solid #FFFFFF;      
        color: #777777;      
        font-size: 14px;      
        font-weight: bold;      
        line-height: 20px;      
        text-shadow: 0 1px 0 #FFFFFF;      
        padding-left: 10px;      
    } 

    .chats li.chat {     
        border-top: 1px solid #ECECEC;      
        line-height: 26px;      
        text-indent: 10px;      
    } 

        /** activeChatView **/     
    .chats li.chat.active {      
        background-image: linear-gradient(center top, #ADBDD7 0pt, #748DBB 100%);      
        background-image: -moz-linear-gradient(center top, #ADBDD7 0pt, #748DBB 100%);      
        background-image: -webkit-linear-gradient(top, #ADBDD7 0pt, #748DBB 100%);      
        box-shadow: 0 1px 0 #899CC0 inset, 0 2px 0 #B4C6E4 inset, 0 -1px 0 #6C7B98 inset;      
        margin: -1px 0 0;      
        text-shadow: 0 1px 1px #474E59;      
        color: #FFF;      
    } 

        /** writer **/     
    .writer {      
        position: fixed;      
        bottom: 0;      
        height: 100px;      
    } 

</style>     
<script src="jquery.js"></script>      
<script src="socket.io.js"></script>      
<script src="underscore.js"></script>      
<script src="backbone.js"></script>      
<script src="app.js"></script>      


这是标题 > 好啊

  • 这是一条
  • 这是一条
  • 这是一条
  • 这是一条
  • 这是一条
  • 这是一条
  • 这是一条
  • 这是一条


从中可以看到,html页面中的代码十分干净,只有html和css定义,没有复杂的js。

app.coffee

root = this
root.App = App =

Models: {}      
Views: {}      
Collections: {}      
chatsView: null      
topicView: null      
writerView: null      
io: null      
initialize: -> 

class App.Models.Chat extends Backbone.Model

defaults:      
    id: null      
    content: ""      
    author: null      
    timestamp: null 

class App.Models.Topic extends Backbone.Model

defaults:      
    id: null      
    title: ""      
    description: "" 

class App.Collections.Chats extends Backbone.Collection

initialize: ->      
    super      
    @io = App.io      
    @io.on("message.send", @on_message_send)      
on_message_send: (msg) =>      
    chat = new App.Models.Chat(msg)      
    @add(chat) 

class App.Collections.Topics extends Backbone.Collection

class App.Views.ChatsView extends Backbone.View

    initialize: ->      
        @collection.bind "add", @addChat      
        @activeChatView = null      
    render: ->      
        @collection.each @addChat      
        @      
    addChat: (model) =>      
        chatView = new App.Views.ChatView(model)      
        $(@el).append(chatView.el)      
    markActive: (chatView) ->      
        $(@activeChatView.el).removeClass("active") if @activeChatView?      
        @activeChatView = chatView      
        $(@activeChatView.el).addClass "active" 

class App.Views.ChatView extends Backbone.View

TEMPLATE : """ <span class="content"><%= content%></span>      
       <span class="timestamp"><%= timestamp%></span>      
       <span class="author"><%= author%></span> 

       """     
tagName: "li"      
className: "chat"      
initialize: (@model) ->      
    model.bind("change", @render)      
    @render()      
render: ->      
    $(@el).html @model.get("content")      
    this      
events:      
    click : "markActive"      
markActive: ->      
    App.chatsView.markActive(@) 

class App.Views.WriterView extends Backbone.View

events:      
    "click .sendBtn" : "send_message"      
    "keyup .writerInput" : "send_message_on_enter"      
send_message: ->      
    input = @$(".writerInput")      
    return unless (value = input.val())?      
    App.io.emit("message.send", content: value)      
    input.val("")      
send_message_on_enter: (event)->      
    @send_message() if event.keyCode == 13 

App.initialize = ->

App.io = root.io.connect("[http://localhost:8081")](http://localhost:8081"))      
chat = new App.Models.Chat(content: "这是个试验1")      
chats = new App.Collections.Chats([chat])      
App.chatsView = new App.Views.ChatsView(collection: chats, el: $(".chats")).render()      
App.writerView = new App.Views.WriterView(el: $(".writer")).render() 

$ ->

App.initialize()

这些coffee代码,与js代码比起来可读性更好一些。当然,它们最终将被转换为js链到页面中。

下面的这些对话,就是我向刘松请教backbone的过程,仔细看一下,基本上就能明白backbone.js是怎么回事了。

我(23246779) 11:49:03
我有backbone方面的问题想问你

刘松(42279444) 12:12:11
我到了。

我(23246779) 12:12:59
backbone到底是用来做什么的
我虽然有个大概的感觉,但还是不太清楚

刘松(42279444) 12:14:08
参考这里的代码:
https://github.com/scalaeye/scalaeye/blob/sliu/html/app.coffee
在js端也使用mvc框架,分离数据、UI的职责

我(23246779) 12:14:45
我看到你的main.html,里面很干净
只有html和css

刘松(42279444) 12:14:37
它也提供了事件抽象。
比方咱们的页面,应该有TopicView(主题界面)、ChatsView(含多个ChatView)和WriterView(输入界面)

刘松(42279444) 12:15:42
这是ui层。
对应backbone就是views

我(23246779) 12:16:16
这几个view在html代码中,有没有表现出来?

刘松(42279444) 12:16:53
对.

刘松(42279444) 12:17:13

comments powered by Disqus