タブUIをBackbone.jsで

http://dev.classmethod.jp/ria/backbone-js-ui-tab/ http://dev.classmethod.jp/news/lesson6-done/

by FiNGAHOLiC

HTML

<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.10/backbone-min.js"></script>
<script type="text/template" id="js-template-tab-nav">
    <li>
        <!-- 最初の1文字をキャメライズしているだけ -->
        <a href="#<%= name %>"><%= name[0].toUpperCase() + name.slice(1) %></a>
    </li>
</script>
<script type="text/template" id="js-template-tab-content">
    <div class="mod-tab-content"><%= content %></div>
</script>
<div class="mod-tab js-tab">
    <ul class="mod-tab-navs js-tab-navs"></ul>
    <div class="mod-tab-contents js-tab-contents"></div>
</div>

CSS

.mod-tab { padding: 30px; font-size: 78%; font-family: helvetica, san-serif; }
.mod-tab-navs { overflow: hidden; _zoom: 1; position: relative; bottom: -1px; }
.mod-tab-navs li { margin-right: 1px; border: 1px solid #355e95; border-bottom: 0; float: left; }
.mod-tab-navs li a { padding: 10px 15px; display: block; background: #355e95; color: white; text-decoration: none; }
.mod-tab-navs li.active a { background: white; color: #355e95; }
.mod-tab-contents { padding: 15px; border: 1px solid #355e95; }
.mod-tab-content { display: none; }
.mod-tab-content.active { display: block; }

JavaScript

var TabView = Backbone.View.extend({
    templateNav: _.template($('#js-template-tab-nav').html()),
    templateContent: _.template($('#js-template-tab-content').html()),
    initialize: function(options){
        this.$container = $('.js-tab');
        this.$container_navs = this.$container.find('.js-tab-navs');
        this.$container_contents = this.$container.find('.js-tab-contents');
        this.name = this.options.data.name;
    },
    render: function(){
        this.$nav = $(this.templateNav(this.options.data));
        this.$content = $(this.templateContent(this.options.data));
        this.$container_navs.append(this.$nav);
        this.$container_contents.append(this.$content);
    },
    activate: function(){
        this.$nav.addClass('active');
        this.$content.addClass('active');
    },
    deactivate: function(){
        this.$nav.removeClass('active');
        this.$content.removeClass('active');
    }
});

var TabApp = _.extend(Backbone.Events, {
    views: [],
    tab_names: [],
    wasRendered: false,
    initialize: function(data){
        _.each(data, function(_data){
            var tabView = new TabView({ data: _data });
            tabView.listenTo(this, 'change', function(name){
                if(tabView.name === name){
                    tabView.activate();
                }else{
                    tabView.deactivate();
                };
            });
            this.views.push(tabView);
            this.tab_names.push(_data.name);
        }, this);
        return this;
    },
    renderAll: function(callback){
        if(!this.wasRendered){
            this.wasRendered = true;
            _.each(this.views, function(view){
                view.render();
            });
            if(callback) callback();
        };
    },
    changeTo: function(name){
        if(_.indexOf(this.tab_names, name) >= 0){
            this.trigger('change', name);
        };
    }
});

var TabRouter = Backbone.Router.extend({
    routes: {
    ...