為了避免腦袋久了變成水母,所以趁現在記憶鮮明的時候先寫下來,這樣以後被起底才會有東西可以爆料。AngularJS 也不算很新,現在大家都在玩 ReactJS 了,反觀我自己關心的 Famo.us 草都這麼高了(比畫胸口
希望有時間回去整理 Famo.us 啊(遠目
參考
Gantt chart component for AngularJS
架構規劃
粗略說明一下,
core
核心的檔案都可以放在這裡面logic
屬於邏輯的程式放這裡ui
屬於使用者介面處理的程式放這裡gagawulala.js
主要的 Appgagawulala.css
主要的樣式檔案
plugins
額外的套件(或者是自己寫的額外的套件放這templates
樣版檔案放這裡
從 Directive 開始
不管你要做什麼事情,總是要自己做一個 Directive 才夠潮,像是 gaGawuLala
之類的!
/* gagawulala.js */
angular.module('gaGawuLala', [])
.directive('gaGawuLala', [function() {
}]);
然後就可以開始定義這個 Directive 初始化應該做些什麼事情,裡面的 $scope
到底需要什麼,需要的話給個 controller
或是 link
來做些比較繁雜的事情。至於 controller
與 link
差異在哪裡,可以參考這一篇文章。
簡單的說就是,
Before compilation? – Controller
After compilation? – Link
邏輯層
能放在 logic
的大部分(或者全部)都是 factory
,這可以當作個人喜好。所以,裡面我們也就會有一個 gagawulala.factory.js
,來定義整個 gaGawuLala
這個應用程序物件。
/* gagawulala.factory.js */
angular.module('gaGawuLala')
.factory('gaGawuLala', ['gaGawuLalaOptions', function(Options) {
var gaGawuLala = function($scope, $element) {
var self = this;
this.scope = $scope;
this.element = $element;
this.options = new Options($scope, {
/* other options here. */
});
};
gaGawuLala.prototype.getMySize = function() {
return 30;
};
return gaGawuLala;
}]);
然後我們用到了一個叫做 gaGawuLalaOptions
的 factory
,目的是要整合物件,所以寫個簡單的合併來用(可以參考這一段原始碼。關於 factory
的部分就不再贅述。
使用者介面層
處理跟使用者有關的部分,大抵上都在這裡,像是 Directive、Filter 或是 Service 之類的東西。這裡特別記錄一下關於參考資料中,所使用的 DirectiveBuilder
這個 Service!
/* gaGawuLalaDirectiveBuilder.service.js */
angular.module('gaGawuLala')
.service('gaGawuLalaDirectiveBuilder', ['$templateCache', function($templateCache) {
var DirectiveBuilder = function DirectiveBuilder(directiveName, templateUrl, require, restrict) {
/* 載入了 directiveName, templateUrl, require 與 restrict 做預處理 */
/* 中間省略一千字 */
};
return DirectiveBuilder;
}]);
原始碼可參考這一段。
這個作法真的頗高明,這樣我在其他的 Directive 要做初始化的時候,只需這樣做即可,
angular.module('gaGawuLala')
.directive('gaGawuLalaMySize', ['gaGawuLalaDirectiveBuilder', function(Builder) {
var builder = new Builder('gaGawuLalaMySize');
return builder.build();
}]);
如果我需要加入 controller
也不麻煩,只要這樣,
angular.module('gaGawuLala')
.directive('gaGawuLalaMySize', ['gaGawuLalaDirectiveBuilder', function(Builder) {
var builder = new Builder('gaGawuLalaMySize');
builder.controller = function($scope, $element) {
/* 嗡嗡嗡 */
};
return builder.build();
}]);
外掛
外掛可以是別人的,也可以是自己的。但是,通常要修改或是使用別人寫好的模組,都會有水土不服的情況發生,最快能避免的方式,大概就是自己再包一層,用來解決一些套件無法,或是需要修改才能做到的事情。
當然,我們也不會希望去動到別人寫好的模組,不然以後升級的債會還不完。
/* gaGawuLala.plugin18x.directive.js */
angular.module('gaGawuLala.plugin18x', ['gaGawuLala', 'ui-tree'])
.directive('gaGawuLalaPlugin18x', ['$compile', '$document', function($compile, $document) {
return {
restrict: 'E',
require: '^gaGawuLala',
scope: {
enabled: '=?',
header: '=?'
},
link: function(scope, element, attrs, gaGawuLalaCtrl) {
/* 以下省略一萬行 */
}
};
}]);
當中可以看到 require: '^gaGawuLala'
這個用法是美妙的,他用來告訴這個 Directive 必須要取得 gaGawuLala
開頭的這個 Controller 才可繼續執行。可以當做是把某個 Directive 必須要相依在某一個 Directive/Controller 底下的概念。
舉例來說,
.directive('screen', function() {
return {
restrict: 'E',
scope: {
hd: '=?'
},
controller: function() {
this.doSomethingScreeny = function() {
alert("screeny!");
}
}
}
})
.directive('decode', function() {
return {
restrict: 'E',
require: '^screen',
scope: {
4k: '=?'
},
link: function($scope, $element, $attrs, screenCtrl) {
$scope.decodeIt = function() {
screenCtrl.doSomethingScreeny();
}
}
}
})
然後你的 DOM 會類似這個樣子,
<div screen>
<div decode>
<button type="button" ng-click="decodeIt()">Decode</button>
</div>
</div>
然而,既然他都是拿 Controller 了,所以,當你的 require
對象,不存在 Controller 的時候,那就會無效,換句話說,你拿到的 screenCtrl
就會是 undefined
了。
樣版
就是寫寫 HTML 這樣,比較有趣的是,我們可以用 $compile
來做一些,原本樣版裡面沒有的東西。例如外掛裡面的特殊樣版,不可能將他整理到核心樣版裡面。所以,在外掛裡面的 Directive 就可以裡用 $compile
的方式,將樣版塞入核心樣版裡(神不知鬼不覺 XD
不過,有好有壞,全部都放核心樣版,當外掛關掉,變成累贅。而外掛如果分開來放,要除錯的時候,有時相對麻煩一些。不過,以開發的流程來看,分開放或許會好一點(畢竟不需要從壓縮過的結果去除錯啊!
小結
今年聽說強迫休耕,難得去年年底的時候稻子收得不錯的說!而且是新種,今年留頭搞不好也不錯!政府打壓農民無極限!
所以,是時候該進軍 ReactJS 了嗎?說好的 Famo.us 呢!