初めてdojoでdom操作
初dojoで色々勉強になった。
以下改修前の作り。
<ul class="news clearfix"> <li class="current" id="tab01"><a onclick="return private.changetab(this, '01')" href="#" id="atag01">タブ1</a></li> <li id="tab02"><a onclick="return private.index.changetab(this, '02')" href="#" id="atag02">タブ2</a></li> <li id="tab03"><a onclick="return private.index.changetab(this, '03')" href="#" id="atag03">タブ3</a></li> <li id="tab04"><a onclick="return private.index.changetab(this, '04')" href="#" id="atag04">タブ4</a></li> <li id="tab05"><a onclick="return private.index.changetab(this, '05')" href="#" id="atag05">タブ5</a></li> <li id="tab06"><a onclick="return private.index.changetab(this, '06')" href="#" id="atag06">タブ6</a></li> </ul> <div id="info"> にゅーす </div>
private.changetabはdev#idの中身を変更してるだけ。
で、クリックされたタブはCSSでリンクすっ飛ばすようにしてたらしい。
こうなっているのを、クリックされたらタブのaタグ削除したいとの事。
で、使ってるJSFWがdojoって罠。使ったこと無い。
まぁいいや。
で、最初はprivate.changetabの中でaタグ削除( dojo.destroy)・追加(dojo.create)とかすればいいやと思ってやってみた。
dojo.provide('private.index'); private['index'] = { changetab : function (tab, tabId) { // ニュースタブにaタグ付与 var liList = dojo.query('.news > li'); dojo.forEach(liList , function(value, index) { var aTag = dojo.query('a', value); // ニュースタブがリンク状態じゃなかったら if(aTag.length < 1) { var text = value.childNodes[0]; var addId = value.id.slice(-2); var a = dojo.create('a',{ href:'#' , onclick : "return private.index.changetab(this, " + addId + ")" // ←これ。 , id:"atag"+addId }); dojo.place(text , a, "first"); dojo.place(a , value, "first"); } }); //選択タブのリンクを除去 var txtNode = dojo.byId('atag' + tabId).childNodes[0]; var liNode = dojo.query('#tab' + tabId)[0]; dojo.place(txtNode , liNode , "first"); dojo.destroy("atag" + tabId); //その他色々処理... } , connectOnClick : function(event) { var id = event.target.id.slice(-2); return private['default'].index.changeTab(event.target, id); } //その他色々処理... }
FF、opera、safari、IE8ではちゃんと動く。
でもIE6、IE7だと見事に動かない。
どこでこけてるのかと思いきや、js上でdom生成したaタグだとonclickで指定した処理よべてない。
IE6、7はイベント処理が他と逸脱しているのでその影響らしい。
この子達とは一生仲良くなれないと再確信した。
そもそもこの状況でonclick属性使うとかいかがなものかと思ったけど。
dojoならここらへんうまいことやってくれているだろう、とイベントハンドラをHTMLから分離してテストしてみたらIE6,7でも処理呼べた。
ので以下に変更↓
<ul class="news clearfix"> <li class="current" id="tab01"><a href="#" id="atag01">タブ1</a></li> <li id="tab02"><a href="#" id="atag02">タブ2</a></li> <li id="tab03"><a href="#" id="atag03">タブ3</a></li> <li id="tab04"><a href="#" id="atag04">タブ4</a></li> <li id="tab05"><a href="#" id="atag05">タブ5</a></li> <li id="tab06"><a href="#" id="atag06">タブ6</a></li> </ul> <div id="info"> にゅーす </div>
/** * レンダリング後にイベント接続 */ dojo.addOnLoad(function() { var newsTab = dojo.query('.news-tab a'); dojo.forEach(newsTab , function(value, index) { dojo.connect(value, "onclick", private['default'].index.connectOnClick); }); }); dojo.provide('private.index'); private['index'] = { changetab : function (tab, tabId) { // ニュースタブにaタグ付与 var liList = dojo.query('.news > li'); dojo.forEach(liList , function(value, index) { var aTag = dojo.query('a', value); // ニュースタブがリンク状態じゃなかったら if(aTag.length < 1) { var text = value.childNodes[0]; var addId = value.id.slice(-2); var a = dojo.create('a',{ href:'#' , id:"atag"+addId }); dojo.place(text , a, "first"); dojo.place(a , value, "first"); dojo.connect(value, "onclick", private['default'].index.connectOnClick); } }); //選択タブのリンクを除去 var txtNode = dojo.byId('atag' + tabId).childNodes[0]; var liNode = dojo.query('#tab' + tabId)[0]; dojo.place(txtNode , liNode , "first"); dojo.destroy("atag" + tabId); //その他色々処理... } , connectOnClick : function(event) { var id = event.target.id.slice(-2); return private['default'].index.changeTab(event.target, id); } //その他色々処理... }
これで意図通りの動きはする。
が、この実装方法だと何度も何度もタブクリックしてると挙動がめっちゃ重くなるという罠が。
完璧にメモリリークしてる…orz
初めて起こしたのでわからない…基礎から出直してきます…
ちなみに同画面でFlashよんでる場合、そっちでなんかおかしいとIEで動いてくれない。
Flash別環境の呼んでてそっちおかしくて確認の時に軽く影響受けて数分あせった。
●2010/10/20 続報
メモリリークは相変わらずですが、一個教えてもらったことが。
読み込み時の処理でstopEvent使うとURLに#つかなくなるよーと教えてもらった。
function(event) { dojo.stopEvent(event); //←これ。 var id = event.target.id.slice(-2); return private['default'].index.changeTab(event.target, id); }
ってことでaタグ作ってるところも#消した。
var a = dojo.create('a',{ // href:'#', ここ。 id:"atag"+addId });
URLに見事#つかない!素敵!
でもIE6だけは付く…orz
●2010/12/06 続報2
結果残しとくのすっかり忘れてた。。。
メモリリークの件、根本原因は解決してませんが、回避策。
今回はSEO対策で
「タブ切り替えの要素にaタグを付けてるのがイヤ」
って要件だったので
「それならいっそaタグ使わないようにすればいんじゃね?」
って事でonclickをliタグに付けて回避した。
ということで、一番最初のHTMLとJSをちょいと改修するだけで事がすんだ。
が、メモリリーク問題は未解決なので全くよろしくない。
こっちはもうちょっと調べる予定。
dojo.connectでconnectOnClick参照したりしてるからこれ自己参照してるんじゃ…?とか思って色々調べ中。