タブパネルのレンダリング

「いや〜、またしてもハマってしまった…。遅延レンダリングだってさ。」
結論を先に書くと、TabPanel を使う時は、

new ExtTabpanl({
     layoutOnTabChange: true,
     items: [item1, item2]
});

と、コンフィグオプションに layoutOnTabChange を設定するのを忘れないように。

ウェブアプリとは思えない UI を実現できる Ext JS といえども、Web アプリの性質上、DOM 上にエレメントを追加し、その属性をいじることでビジュアルを作っている。タブを実現するのに、アクティブでないパネルを css で hidden にする手もあるが、見えなくとも大量のエレメントを DOM に追加するとなると、とても重い処理になってしまう。で、遅延レンダリング。これは、タブがアクティブになった時に DOM に追加する方法で実現している…らしい。

TabPanel のリファレンス

deferredRender : Boolean

Internally, the TabPanel uses a Ext.layout.CardLayout to manage its tabs. This property will be passed on to the layout as its Ext.layout.CardLayout.deferredRender config value, determining whether or not each tab is rendered only when first accessed (defaults to true).

TabPanel はタブの管理に Ext.layout.CardLayout を使っています。この属性は Ext.layout.CardLayout.deferredRender のコンフィグとしてレイアウトに渡されます。それぞれのタブが初回アクセス時のみレンダリングされるか、そうでないかを決定するために (デフォルトは true)。

なるほど、なるほど。で、CardLayout はどうなってる?

CardLayout のリファレンス

deferredRender : Boolean

True to render each contained item at the time it becomes active, false to render all contained items as soon as the layout is rendered (defaults to false). If there is a significant amount of content or a lot of heavy controls being rendered into panels that are not displayed by default, setting this to true might improve performance.

それぞれのアイテムのアクティブ時にレンダリングするためには true にします。レイアウトのレンダリング時にすべてのアイテムをレンダリングするためには false にします (デフォルトは false)。もし、アイテムが多数であるか、重い多数のコントロールアイテムがデフォルトでは表示されないパネル内にあれば、これを true に設定するとパフォーマンスが向上するかもしれません。

なぜか、デフォルト値が逆だが、それはさておき…。作成中のアプリは、大量のタブがある訳ではないので、遅延レンダリングを false にしてみた。…んが…。最初に非表示となっているタブ (少々複雑なレイアウトになってる) をアクティブにしたところ、レイアウトが乱れまくり〜。(TT)

で、独自に実装していたのだが、レイアウトのデバッグの四苦八苦に疲れてきたところで、こんなのを発見。

TabPanel のリファレンス

layoutOnTabChange : Boolean

Set to true to do a layout of tab items as tabs are changed.

変更されたタブアイテムをレイアウトするために true にします。

早速、試してみたところ、うまくいった。今までの苦労はなんだったのか…。(--; こいつは、デフォルトで true にしておいてほしかった…。(^^;