closure-library始める3 uiコンポーネントについての続き
enterDocumentはDOMが作成されて、document上に配置された時に呼ばれる。だから、イベントリスナーを張るのに適した場所だ。
その前に、プロパティに、goog.events.EventHandlerを持っておく。
goog.require('goog.events.EventHandler'); //略 hoge.Box = function(opt_label,opt_domHelper){ … this.eh_ = new goog.events.EventHandler(this); … }
これ、なんでEventHandlerをわざわざプロパティに持っておくのかな...と思ったら、new goog.events.EventHandler(this)としておくことで、このオブジェクトを使ってlistenさせるとその時のthisがEventHandlerのコンストラクタで渡したオブジェクトになるのね。
というか、このオブジェクトがEventHandlerって名前は微妙におかしくないか...?
hoge.Box.prototype.enterDocument = function(){ goog.base(this,"enterDocument"); this.eh_.listen(this.getElement(),goog.events.EventType.CLICK, function(){alert('clicked ' + this.label_)}); };
goog.base(this,"enterDocument")で、スーパークラスのenterDocumentを呼んでいる。で、その後、自分のルート要素のイベントをlistenする。最後の関数でthis.label_を呼び出せているのがポイント。
...この方が簡単だと思って、無名関数使ったが、unlistenもあるので、元ソースと同じように変更する。
で、enterDocumentと対になっているのがexitDocumentで、ここでイベントリスナーを外しておかないと、オブジェクトがリークして後々大変なことになったりするのでしょう。まとめると
hoge.Box.prototype.enterDocument = function(){ goog.base(this,"enterDocument"); this.eh_.listen(this.getElement(),goog.events.EventType.CLICK, this.onDivClicked_); }; hoge.Box.prototype.exitDocument = function(){ goog.base(this,"exitDocument"); this.eh_.unlisten(this.getElement(),goog.events.EventType.CLICK, this.onDivClicked_); }; hoge.Box.prototype.onDivClicked_ = function(event){ alert(this.label_); };
で、DOM関連の後始末はexitDocumentで行って、そのほかのオブジェクトの破棄は、disposeInternalで行う。
hoge.Box.prototype.disposeInternal = function(){ goog.base(this,"disposeInternal"); this.eh_.dispose(); };
これで非常に簡単なコンポーネントができた。こうやってみると、意外とわかりやすい?。
script/apps.js
goog.provide('hoge.App'); goog.require('hoge.Box'); hoge.App = function(){ this.initialize_(); } hoge.App.prototype.initialize_ = function(){ var he = new hoge.Box(); he.render(document.body); }; new hoge.App();
script/box.js
goog.provide('hoge.Box'); goog.require('goog.ui.Component'); goog.require('goog.events.EventHandler'); hoge.Box = function(opt_label,opt_domHelper){ goog.ui.Component.call(this,opt_domHelper); this.label_ = opt_label || 'Click Me'; this.eh_ = new goog.events.EventHandler(this); this.initialize_(); } goog.inherits(hoge.Box,goog.ui.Component); hoge.Box.prototype.initialize_ = function(){ }; hoge.Box.prototype.createDom = function(){ this.decorateInternal(this.dom_.createElement('div')); }; hoge.Box.prototype.decorateInternal = function(element){ this.setElementInternal(element); this.dom_.setProperties(element, {"style":"border: 1px solid black; width: 150px; background-color: gray; color: white; text-align: center; font-weight: bold;"}); if(!this.getLabelText()){ this.setLabelText(this.label_); } }; hoge.Box.prototype.getLabelText = function(){ if(!this.getElement()){ return ''; } return this.dom_.getTextContent(this.getElement()); }; hoge.Box.prototype.setLabelText = function(text){ if(this.getElement()){ this.dom_.setTextContent(this.getElement(), text); } }; hoge.Box.prototype.enterDocument = function(){ goog.base(this,"enterDocument"); this.eh_.listen(this.getElement(),goog.events.EventType.CLICK, this.onDivClicked_); }; hoge.Box.prototype.exitDocument = function(){ goog.base(this,"exitDocument"); this.eh_.unlisten(this.getElement(),goog.events.EventType.CLICK, this.onDivClicked_); }; hoge.Box.prototype.disposeInternal = function(){ goog.base(this,"disposeInternal"); this.eh_.dispose(); }; hoge.Box.prototype.onDivClicked_ = function(event){ alert(this.label_); };