-
Notifications
You must be signed in to change notification settings - Fork 12
1.x tutorial index index js
トップページでは、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モジュールに配置しますが、サブモジュールとは完全に分離されているので、任意の場所に配置可能です。
HTMLロード時の最初の Controller
です。
RootView
, RootModel
の設定・各種初期セットアップを行い、初回ページを構築します。各モジュールはこのJavaScriptファイルで記述されたものが使用されます。
Backbone.jsのMVC モデルでは、Controller相当の機能は Backbone.js#Router に内包する形で実装されていますが、Beezでは、Routerとは別に明示的にControllerを提供しています。
BeezのArchitectureでは、MVCRモデルという名前になります。詳しくは、Architecture を参照ください。
====
/**
* @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には複数のモジュール定義パターンがあります。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)
このページで紹介する処理が全て完了したあとに、searchモジュールへ処理を渡します。
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)
Controllerで定義した、mm.rootの'Model'になります。
オブジェクトコンテナは、ツリー構造で管理されていますので、rootは管理上必要な空の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('/@');
<body>
の直下に唯一配置される<div>
タグです。
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#extendのtagName
です。
id
view
に対応するDOM Elementのid属性です。
Backbone.View#extendのid
です。
vidx
このViewのインデックスで、Beez.MVCRのオブジェクトコンテナで管理される際に使用されるIDになります。 管理しているViewの操作をするさいに使用します。
root()関数に入れる場合は、
@
を指定してください。@
を別の文字列に変更することも可能ですが、無理に変える必要はありません。
オブジェクトコンテナからの取得
var rootView = beez.manager.get('/@');
render
Backbone.View#View-renderのrender
です。
ページの「ヘッダー」「コンテンツ」「フッター」別の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がテンプレートの表示します。
====
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 は自動生成されるため、触る必要はありません。
====
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": {}
}
}
}
},
beez-foundationによる開発サーバーを利用している場合、設定ファイルやJavaScript、Handlebars、Stylusは自動更新・自動コンパイルされます。 手動でコマンドを打つ必要はありません。各ファイルを編集して保存するだけで問題なく開発が進められます。