Skip to content

Latest commit

 

History

History
385 lines (310 loc) · 13.1 KB

README.md

File metadata and controls

385 lines (310 loc) · 13.1 KB

内容导航

##1. Chassis是什么?

Chassis源于百度内部的Rocket项目,是一套以提高Webapp开发效率为目的的开发框架。它提供了一套类Backbone的MVC代码架构,在此基础上延伸了视图层管理,优化了路由控制以及更加轻量级的实现。此外,基于Chassis的视图分层和开发规范,可以实现非常灵活的分工协作。

##2. Chassis有多轻量级?

Chassis在实现上采用了多种组件化方案,开发者可以根据需求实现灵活定制。在体积上,轻量级版本Chassis只有 4.8KB (gzip)。

##3. Chassis适合什么样开发场景?

如果你的项目满足以下特点(或需求)将会非常适合使用Chassis作为开发框架:

  • 单页面应用(SPA)
  • 路由管理
  • 视图管理(视图分层、视图切换、视图智能回收等)

##4. Chassis入门

假设我们需要开发一个非常简单的APP,由两个页面组成:一个列表页以及一个详情页。APP默认页面为列表页,点击列表页会切换到详情页。

PC请点击此处查看效果 source

手机请访问 t.cn/zH0WkZn

###4-1. 准备工作

首先我们需要引入基础的JS脚本库。Chassis本身唯一的依赖是DOM脚本库,你可以选择使用zeptojQuery或者ender

此外,在实际项目中通常还需要用到前端模板,因此还需要引入模板库,例子中使用的是Mustache

最后引入Chassis,这样脚本库的准备工作就完成了。

<script src="js/zepto.js"></script>
<script src="js/mustache.js"></script>
<script src="js/chassis.js"></script>

###4-2. 路由规则

接下来我们需要确定APP的路由规则,这直接影响到视图层的组织。本例中包含两个页面:首页以及详情页,我们给每个页面分配一个ID:indexdetail。页面对应的访问路径分别是:http://yourdomain.comhttp://yourdomain.com#/detail/123

index页面由于为首页而且无参数,因此它对应的路由规则为空字符串;

detail页面需要参数来获取数据,因此detail页面对应的路由为/detail/123,为了在页面初始化时能够获得参数,我们把detail页面的路由规则定义为detail/:albumId

接下来我们就可以初始化路由管理了。

Chassis.history.start( {
    router: {
        routes: [ '', 'detail/:albumId' ]
    } 
} );

以上的路由定义含义为:当URL中路由路径为空以及detail/:albumId时会切换到相应的视图;detail/:albumId则对应detail视图。Chassis中空路径默认对应ID为index的视图,因此路由规则可以简化:

routes: [ 'detail/:albumId' ]

如果实际应用中路由规则中的字符串无法和视图ID对应则可以换用以下方式:

routes: {
    // 空路由会定位到home视图
    '': 'home',
    // 定位到album视图
    'detail/:albumId': 'album'
}

更多信息请参考《Chassis的路由使用》

###4-3. 开发首页

在路由确定后我们就可以正式进行视图开发了,让我们先来完成首页。

首先,我们需要为页面数据的显示准备相应的模板,这里使用Mustache语法,如下。

####4-3-1. 模板

<script id="index-template" type="text/x-template">
    <div class="hd log url  need-active">   
        <h2>专辑热榜</h2>
        <div></div>
    </div>
    <ul class="list">
        {{#list}}
        <li class="song url log song-40153340">
                <div class="left">
                    <div class="rank equal">{{rank}}</div>
                    <div class="info">
                        <a href="#detail/{{album_id}}">
                            <b>{{title}}</b>
                            <span class="txt">{{author}}</span>
                        </a>
                    </div>
                </div>
                <div class="download need-active">下载</div>
        </li>
        {{/list}}
    </ul>
</script>

现在我们需要定义视图对应的数据。

####4-3-2. Model

Chassis.Model.define( 'index', {
    url : function() {
        return 'data/albums.php';
    },
    parse : function( resp ) {
        var album_list = resp.plaze_album_list.RM.album_list,
            list = album_list.list;
        for( var i = 0, len = list.length; i < len; i++ ) {
            list[ i ].rank = i + 1;
        }
        return album_list;
    }
} );

通过Chassis.Model.define接口可以定义数据Model, 第一个参数为Model的ID, 建议和对应视图的ID保持一致,第二个参数为Model原型方法和属性。

这里使用了urlparse方法,url返回的结果会作为获取数据的目标路径;parse返回的结果会作为Model的最终数据。

更多信息请参考《Chassis的模型使用》

这之后就是视图的定义了。

####4-3-3. 视图

Chassis.PageView.define( 'index', {
    // 设置PageView所在的DOM
    el: '#album-list',
    // 配置事件
    events: {
        // 监听model change
        'change model': 'onModelChange'
    },
    init: function( opts ) {
        this.model = Chassis.Model.create( 'index' );
    },
    // 在APP路由到当前页面之前会调用该方法
    onBeforePageIn: function() {
        // 获取数据
        if ( !this.model.fetched ) {
            this.showLoading();
            this.model.fetch();
            this.model.fetched = true;
        }
    },
    onModelChange: function( ) {
        // 渲染模板并输出
        this.$el.html( 
            Mustache.render( $( '#index-template' ).html(), 
                this.model.toJSON() )
        );
        // 隐藏Loading
        this.hideLoading();
    }
} );

接下来详细介绍一下如何定义一个视图。

首先你需要了解Chassis.PageView.define接口。该接口接收两个参数,第一个参数为页面的ID,与路由规则中的ID一一对应;第二个参数则为视图原型的属性和方法。

在原型上:

el: '#album-list',

设置视图所关联的DOM结点,在视图中this.$el可以获得DOM的jQuery封装对象。 它是整个视图的宿主DOM结点,视图的切换、显示、隐藏以及默认的事件等都作用在结点上。

events: {
    // 监听model change
    'change model': 'onModelChange',
    // 监听model error
    'error model': 'onModelError'
},

通过events对象可以统一配置各种事件的处理方法,这里不仅仅能配置内部DOM结点的事件,还包括了view、model以及document和window。

  • 'click .btn': handler :点击this.$el上class为.btn的DOM结点;
  • 'change model: handler' :监听this.modelchange事件;
  • 'beforepagein view': handler :监听当前视图的beforepagein事件;
  • 'click window': handler :点击window;
  • 'click document': handler :点击document;

通过events对象配置的事件,在调用视图的destroy方法后都能被正确移除, 因此建议事件统一在此配置。

init: function( opts ) {
    this.model = Chassis.Model.create( 'index' );
},

定义初始化操作,这里在初始化时创建了视图对应的数据Model。

onBeforePageIn: function() {
    // 获取数据
    if ( !this.model.fetched ) {
        this.showLoading();
        this.model.fetch();
        this.model.fetched = true;
    }
},

onBeforePageIn方法在视图即将切换到当前视图之前会自动调用, 你可以在此进行视图展示前的预处理,比如此处会提前显示loading效果并请求数据。对应的还有onAfterPageInonBeforePageOut以及onAfterPageOut方法。

onModelChange: function( ) {
    // 渲染模板并输出
    this.$el.html( 
        Mustache.render( $( '#index-template' ).html(), 
            this.model.toJSON() )
    );
    // 隐藏Loading
    this.hideLoading();
}

此处监听Model数据,在数据返回后会获取页面模板进行渲染,最后因此loading。

至此,首页的代码就完成了。

###4-4. 开发详情页

####4-4-1. 模板

<script id="detail-template" type="text/x-template">
    <header id="header" class="">
        <div class="bar">
            <div class="left">
                <a href="#"><span class="btn need-active btn-back"></span></a>
            </div>
             <h1 class="">{{albumInfo.title}}</h1>
             <div class="right"></div>
        </div>
    </header>
    <section class="content">
        <div class="topic">
            <div class="mod">
                <div class="pic">
                    <img alt="{{albumInfo.title}}" src="{{albumInfo.pic_small}}">
                </div>
                <div class="info">
                    <p data-info="{{albumInfo.info}}">
                        {{albumInfo.simpleinfo}}
                        <a class="expand">展开</a>
                    </p>
                    <time class="txt">创建时间:{{albumInfo.publishtime}}</time>
                </div>
            </div>
            <ul class="list withbar">
                <li class="hd">{{albumInfo.title}}</li>
                <ul class="list">
                    {{#songlist}}
                    <li class="song url log song-50902704">
                        <div class="left">
                            <div class="rank">{{rank}}</div>
                            <div class="info">
                                <b>{{title}}</b>
                                <br>
                                <span class="txt">{{author}}</span>
                            </div>
                        </div>
                        <div class="download need-active">下载</div>
                    </li>
                    {{/songlist}}
                </ul>
            </ul>
        </div>
    </section>
</script>

####4-4-2. Model

Chassis.Model.Detail = Chassis.Model.extend( {
    url : function() {
        return 'data/info.php';
    },
    
    parse : function( resp ) {
        var list = resp.songlist;
        resp.albumInfo.simpleinfo = resp.albumInfo.info.substring(0, 70) + '...';
        for( var i = 0, len = list.length; i < len; i++ ) {
            list[ i ].rank = i + 1;
        }
        return resp;
    }
} );

####4-4-3. 视图

Chassis.PageView.define( 'detail', {
    // 设置PageView所在的DOM
    el: '#album-detail',
    // 配置事件
    events: {
        // 监听model change
        'change model': 'onModelChange',
        // expand
        'click .expand': 'onExpand'
    },
    init: function( opts ) {
        this.model = new Chassis.Model.Detail();
    },
    // 在APP路由到当前页面之前会调用该方法
    onBeforePageIn: function( e ) {
        this.$el.html( '' );
        this.showLoading();
        // 获取数据
        this.model.fetch({
            data : {
                id : e.params.albumId
            }
        });
        
    },
    onModelChange: function( ) {
        // 渲染模板并输出
        this.$el.html( 
            Mustache.render( $( '#detail-template' ).html(), 
                this.model.toJSON() )
        );
        // 隐藏Loading
        this.hideLoading();
    },
    onExpand: function( e ) {
        e.preventDefault();
        var $info = this.$( '.mod .info p' );
        $info.html( $info.attr( 'data-info' ) );
    }
} );

到此一个最简单的Chassis应用就开发完了,关于Chassis的更多细节请参考:

##5. 更多文档

Chassis入门文档