Skip to content

1.x tutorial index index js

fkei edited this page Feb 17, 2014 · 2 revisions

index モジュール

概要

トップページでは、1ページの中でヘッダー、コンテンツ、フッターの3つのビューを作成して画面を表示しています。

Beezは、require.js#packages を利用し、サブモジュール(パッケージ分割)開発をサポートしています。

サブモジュールとは

Beezは、サブモジュールを一つの機能・一つの画面と言った単位で、JavaScriptファイルを分割して、必要なったタイミングで個別にJavaScriptファイルをロードしていく仕組みです。

分割単位は特に決まりはありません。好きな単位で分割可能です。モジュールを使わずに開発していくことも可能ですが、規模が大きくなっていくにつれてモジュールに分割して違うページで再利用したい場面が多くなるでしょう。

チュートリアルは、s/{サブモジュール} というディレクトリ構成で構築されています。

チュートリアルのサブモジュールディレクトリ構成

$ tree s/index/
s/index/
├── hbs
│   ├── footer.hbs
│   ├── footer.hbsc.js
│   ├── header.hbs
│   └── header.hbsc.js
├── index.html.hbs
├── index.js
├── local.develop.html
├── local.release.html
├── model
│   └── index.js
├── require.beez.js.hbs
├── require.beez.local.develop.js
├── require.beez.local.release.js
├── styl
│   ├── index.css
│   └── index.styl
└── view
    ├── content.js
    ├── footer.js
    ├── header.js
    └── index.js

4 directories, 18 files

前述した、index.html, require.beez.js.hbs は、便宜上indexモジュールに配置しますが、サブモジュールとは完全に分離されているので、任意の場所に配置可能です。

ファイル別 機能説明

index.js (Controller)

HTMLロード時の最初の Controller です。

RootView, RootModel の設定・各種初期セットアップを行い、初回ページを構築します。各モジュールはこのJavaScriptファイルで記述されたものが使用されます。

Controller とは

Backbone.jsのMVC モデルでは、Controller相当の機能は Backbone.js#Router に内包する形で実装されていますが、Beezでは、Routerとは別に明示的にControllerを提供しています。

BeezのArchitectureでは、MVCRモデルという名前になります。詳しくは、Architecture を参照ください。

====

index.js

/**
 * @name index.js<index>
 * @author <author>
 * @overview entry point of this project
 */

define(function (require, exports, module){
    'use strict';

    var beez = require('beez');
    var Backbone = beez.vendor.backbone;

    var logger = beez.getLogger('index.index');

    var mv = beez.manager.v; // Viwe Manager
    var mm = beez.manager.m; // Model Manager

    /**
     * Index Controller class
     *
     * @namespace index
     * @class
     * @name IndexController
     * @extends {beez.Controller}
     * @see beez.Controller
     */
    var IndexController = beez.Controller.extend(
        'index.IndexController',
        {
            css: [
                'http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.0/css/bootstrap.css',
                '/index/styl/index.css'
            ],

            /**
             * The set-up the controller
             *
             * @memberof IndexController
             * @name setup
             * @param {function} callback
             * @return {IndexController}
             */
            setup: function setup(callback) {

                // Setup Root View and Model
                var IndexView = require('index/view/index');
                mv.root(IndexView);

                var HeaderView = require('index/view/header');
                mv.create('/@', HeaderView);

                var ContentView = require('index/view/content');
                mv.create('/@', ContentView);

                var FooterView = require('index/view/footer');
                mv.create('/@', FooterView);

                var IndexModel = require('index/Model/index');
                mm.root(IndexModel);

                callback && callback();
                return this;
            },

            /**
             * Routing: index
             *
             * @memberof IndexController
             * @name index
             */
            index: function index() {
                mv.get('/@').async().show().then(function() {
                    beez.manager.r.navigate('search', true);
                }).end();
            }
        }
    );

    return IndexController;


});

コード説明

define(function (require, exports, module){

require.jsのシンプルCommonJS define を使用しています。

require.js#cjsmodule

require.jsには複数のモジュール定義パターンがあります。Beezではこの定義方法を推奨しますが、require.jsがサポートするモジュール定義はすべて利用可能です。

css

コントローラが生成されたタイミングで、cssで定義したCSSをDOM上で<style>タグとして追加します。

実際の開発では*.cssではなく*.stylを編集していきます。 *.cssは compileされたCSSファイルです。リリース時はこちらが配信され使用するので、*.stylは使用しません。 Stylusについて詳しくは、Stylus - executable を参照ください。

setup()

トップページで使用するControllerのセットアップ処理を関数に切り出したものです。チュートリアル用に作っている関数なので、beezの機能というわけではありません。

mv.root. mm.root

Beez.Managerで管理されるオブジェクトコンテナはツリー構造で構成されます。利用する前に必須でrootを設定する必要があります。

View, Model Classは、後述します。

indexモジュールのviewManager ツリー構造

ツリー構造の設定はJSONPathに準じています。

root # index/view/index.js js : jsonpath=/@
├── header # index/view/header.js : jsonpath=/@/header
├── content # index/view/content.js : jsonpath=/@/content
├── foot# index/view/footer.js : jsonpath=/@/footer

/@がrootとして使用されます。/@/headerと指定するとrootの配下に子供としてheaderとして配置されます。 このように親子関係をツリー構造で指定することにより、オブジェクトコンテナの扱いが簡単になるのがBeezの特徴になっています。

index()

Routerに登録されている関数です。Routerについては後述します。

mv.get('/@').async().show()

指定されたViewのツリーにある子孫すべての表示処理(render)するshowという関数です。

then()は、一般的な非同期ライブラリと同じで、show()が成功した場合のみ実行される関数です。

show()とは逆の処理を行う hide() もあります。

beez.manager.r.navigate('search', true)

Backbone.Router#navigator です。

このページで紹介する処理が全て完了したあとに、searchモジュールへ処理を渡します。

Router

Beezの、サブモジュール開発でのモジュール間の処理は、すべてRouterに登録されたController関数を入り口として処理を行います。

BeezのRouter定義は、設定ファイルで全て定義されています。

conf/local/develop.json

{
    "develop": { // enviroment name
        ....
        // Setting require.js
        "requirejs": {
            ....
            "config": {
                // configuration information used by beez
                "beez.core": {
                    ....
                    // backbone#router
                    "router": {
                        "*default": {
                            "route": "*default",
                            "name": "index",
                            "require": "index/index",
                            "xpath": "/@/index"
                        },
                        "search": {
                            "route": "search",
                            "name": "searchIndex",
                            "require": "search/index",
                            "xpath": "/@/search"
                        }
                    }
                }
            }
        }
    }
}
  • router.key : 任意の識別キー
    • route : route ハッシュマップとパラメータ定義 @see Backbone.js.Router#routes
    • require : routeにマッチした際に、呼び出されるController (@see require.js)
    • name : routeにマッチした際に、呼び出されるControllerの関数
      • routerに登録される関数すべてを一位にすることを推奨
    • xpath : routeにマッチした際に、呼び出されるControllerインスタンスパス (beez.manager.controller)

model/index.js(Model)

Controllerで定義した、mm.rootの'Model'になります。

オブジェクトコンテナは、ツリー構造で管理されていますので、rootは管理上必要な空のModelでも構いません。 すべてのModelを一度に取得する際などに利用します。

Model とは

Backbone.jsのMVC モデルでいうところの、Model になります。 基本的に、Backbone.js#Model と同等の機能を有しています。

====

/**
 * @name index.js<index/model>
 * @author <author>
 * @overview model of index
 */

define(function __IndexModel__(require, exports, module){
    'use strict';

    var beez = require('beez');
    var logger = beez.getLogger('model.index');

    var mv = beez.manager.v;
    var mm = beez.manager.m;

    /**
     * Index Model class (Root)
     *
     * @namespace index
     * @class
     * @name IndexModel
     * @extends {beez.Model}
     * @see beez.Model
     */
    var IndexModel = beez.Model.extend(
        'index.model.IndexModel',
        {
            /**
             * Index path model manager
             *
             * @memberof RootModel
             * @name midx
             * @type {String}
             * @readonly
             */
            midx: '@'

            //

        }
    );

    return IndexModel;
});

説明上、Modelを別ファイルで作成しましたが、下記のコードの用にController等にまとめて書くことも可能です。

....
var RootModel = new beez.Model.extend(
    'index.model.IndexModel',
    {
        midx: '@'
    }
);
....

コード説明

midx

このModelのインデックスで、Beez.MVCRのオブジェクトコンテナで管理される際に使用されるIDになります。 管理しているModelの操作をするさいに使用します。

root()関数に入れる場合は、@を指定してください。 @を別の文字列に変更することも可能ですが、無理に変える必要はありません。

オブジェクトコンテナからの取得

var rootModel = beez.manager.get('/@');

view/index.js (View)

<body>の直下に唯一配置される<div>タグです。

View とは

Backbone.jsのMVC モデルでいうところの、View になります。 基本的に、Backbone.js#View と同等の機能を有しています。

beez.Viewでは、さらに拡張し利便性の高い機能を提供します。

====

/**
 * @name index.js<index/view>
 * @author <author>
 * @overview view of index
 */

define(function(require, exports, module) {
    'use strict';

    var beez = require('beez');
    var $ = beez.vendor.$;
    var mcss = beez.manager.css;
    var logger = beez.getLogger('index.view.index');

    /**
     * View class
     *
     * @namespace index
     * @class
     * @name IndexView
     * @extends {beez.View}
     * @see beez.View
     */
    var IndexView = beez.View.extend(
        'index.view.IndexView',
        {
            /**
             * $el.name
             *
             * @memberof IndexView
             * @name tagName
             * @type {String}
             * @override Backbone.View.tagName
             * @readonly
             */
            tagName: 'section',

            /**
             * $el.id
             *
             * @memberof IndexView
             * @name id
             * @type {String}
             * @override Backbone.View.id
             * @readonly
             */
            id: 'tutorial',

            /**
             * Index path view manager
             *
             * @memberof IndexView
             * @name vidx
             * @type {String}
             * @override beez.View
             * @readonly
             */
            vidx: '@',

            /**
             * DOM rendering
             *
             * @memberof IndexView
             * @function
             */
            render: function render() {
                $('body').append(this.$el);
            }
        });

    return IndexView;
});

コード説明

tagName

view に対応するDOM Elementのタグ名です。

Backbone.View#extendtagNameです。

id

view に対応するDOM Elementのid属性です。

Backbone.View#extendidです。

vidx

このViewのインデックスで、Beez.MVCRのオブジェクトコンテナで管理される際に使用されるIDになります。 管理しているViewの操作をするさいに使用します。

root()関数に入れる場合は、@を指定してください。 @を別の文字列に変更することも可能ですが、無理に変える必要はありません。

オブジェクトコンテナからの取得

var rootView = beez.manager.get('/@');

render

Backbone.View#View-renderrenderです。

view/(header|content|footer).js (View)

ページの「ヘッダー」「コンテンツ」「フッター」別のViewです。

order

beez.View.showを実行する際に、どの順番で実行して欲しいかわかりません。 そういったケースでは、orderに順番(Number)を記述して表示順を決めます。

/**
 * Display order
 *
 * @memberof HeaderView
 * @name order
 * @type {Integer}
 * @override beez.View
 */
order: 0,

this.getParent()

テンプレート (Handlebars)

Handlebars.precompileされたindex/hbs/footer.hbscをrequire.jsでロードし、 自身のElement($el)に設定し、それを親Viewに追加します。

実際の開発では*.hbsc.jsではなく*.hbsを編集していきます。 *.hbsc.jsは precompileされたJavaScriptファイルです。リリース時はこちらが配信され使用するので、*.hbsは使用しません。 Handlebarsについて詳しくは、Handlebars - precompilation を参照ください。

....

var template = require('index/hbs/footer.hbsc');

/**
 * View class
 *
 * @namespace index
 * @class
 * @name FooterView
 * @extends {beez.View}
 * @see beez.View
 */
var FooterView = beez.View.extend(
    'index.view.FooterView',
    {
        ....
        render: function render() {
            var t = template();
            this.getParent().$el.append(this.$el.html(t));
    }
);

....

template()

引数にObjectを渡すと、hbsファイル内でそのObjectが使用してHandlebarsがテンプレートの表示します。

hbs/(header|footer).hbs (Handlebars)

====

header.hbs

<nav class="navbar navbar-inverse navbar-static-top" role="navigation">
<div class="navbar-header">
  <a class="navbar-brand" href="#search">Github API with Beez</a>
</div>

<div class="collapse navbar-collapse">
  <ul class="nav navbar-nav navbar-right">

    <form class="navbar-form navbar-left" role="search" action="https://www.google.com/search" method="GET" target="_blank">
      <input type="hidden" name="as_sitesearch" value="github.com">
      <div class="form-group">
        <input type="text" class="form-control" placeholder="Search github.com" name="as_q">
      </div>
      <button type="submit" class="btn btn-info btn-sm">
        <i class="glyphicon glyphicon-new-window"></i>
        Search
      </button>
    </form>


  </ul>
</div><!-- /.navbar-collapse -->
</nav>

header.hbsc.js

define(['beez'], function(beez) {
  var Handlebars = beez.vendor.Handlebars;
  var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
templates['header'] = template(function (Handlebars,depth0,helpers,partials,data) {
  this.compilerInfo = [4,'>= 1.0.0'];
helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
  var buffer = "", stack1, functionType="function", escapeExpression=this.escapeExpression;


  buffer += "<nav class=\"navbar navbar-inverse navbar-static-top\" role=\"navigation\">\n  <div class=\"navbar-header\">\n    <a class=\"navbar-brand\" href=\"#search\">Github API with Beez - ";
  if (stack1 = helpers.name) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
  else { stack1 = (depth0 && depth0.name); stack1 = typeof stack1 === functionType ? stack1.call(depth0, {hash:{},data:data}) : stack1; }
  buffer += escapeExpression(stack1)
    + "</a>\n  </div>\n\n  <div class=\"collapse navbar-collapse\">\n    <ul class=\"nav navbar-nav navbar-right\">\n\n      <form class=\"navbar-form navbar-left\" role=\"search\" action=\"https://www.google.com/search\" method=\"GET\" target=\"_blank\">\n        <input type=\"hidden\" name=\"as_sitesearch\" value=\"github.com\">\n        <div class=\"form-group\">\n          <input type=\"text\" class=\"form-control\" placeholder=\"Search github.com\" name=\"as_q\">\n        </div>\n        <button type=\"submit\" class=\"btn btn-info btn-sm\">\n          <i class=\"glyphicon glyphicon-new-window\"></i>\n          Search\n        </button>\n      </form>\n\n\n    </ul>\n  </div><!-- /.navbar-collapse -->\n  </nav>";
  return buffer;
  });
    return templates['header'];});

header.hbsc.js は自動生成されるため、触る必要はありません。

styl/index.styl (Stylus)

====

index.styl

html,body
  height 100%
  width 100%

#tutorial
  width 100%
  position relative
  height auto !important
  height 100%
  min-height 100%

#content
  padding-bottom 86px

#footer
  width 100%
  position absolute
  bottom 0
  padding-top 2em
  background-color #333
  color white
  padding-bottom 2em

  ul li
    list-style-type none
    text-align right

index.css

html,body{height:100%;width:100%}
#tutorial{width:100%;position:relative;height:auto !important;height:100%;min-height:100%}
#content{padding-bottom:86px}
#footer{width:100%;position:absolute;bottom:0;padding-top:2em;background-color:#333;color:#fff;padding-bottom:2em;}
#footer ul li{list-style-type:none;text-align:right}

index.css は自動生成されるため、触る必要はありません。

Stylus option

conf/local.json

開発サーバーやビルドコマンドが、自動でStylusをコンパイルしますがコンパイルオプションは設定ファイルに記述します。

詳しくは、Stylus - executableを参照ください。

{
    ....
    "stylus": {
        "options": {
            "encode": "utf-8",
            "compress": true,
            "firebug": false,
            "linenos": false,
            "nib": true, // stylus nib on/of
            "url": {}, // @see http://learnboost.github.io/stylus/docs/functions.url.html
            "fn": {} // variable that can be used with stylus file
        },
        "extend": { // Overwrite the case of mobile data
            "condition": {
                "ua": [ "android", "ios" ]
            },
            "content": {
                "options": {}
            }
        }
    }
},

TIPS

beez-foundationによる開発サーバーを利用している場合、設定ファイルやJavaScript、Handlebars、Stylusは自動更新・自動コンパイルされます。 手動でコマンドを打つ必要はありません。各ファイルを編集して保存するだけで問題なく開発が進められます。

Clone this wiki locally