Lightning コンポーネント開発 TIPS: コンポーネントの縦横比を固定する


今回は Lighting コンポーネントの縦横比の固定方法についてです。
Lighting コンポーネントは通常、画面サイズの変更などにより、レスポンシブに横幅のみが伸縮し縦横比が変化してしまいます。
この縦横比を固定する事で高さも合わせて変化するようにしてやろうというのが今回の挑戦になります。

サンプルコードと動作検証

んで、サクッと作ってみたのがこちら。

FixedAspectRatio.cmp
<aura:component implements="flexipage:availableForAllPageTypes" access="global" >

    <!-- Global Attributes -->
    <aura:attribute name="ratio"  type="Double" access="global" default="1" />

    <!-- Private Attributes -->
    <aura:attribute name="height" type="Double" access="private" />

    <!-- User Interface -->
    <!-- 横幅の変化に合わせてコンポーネント全体の高さを変更したいので、-->
    <!-- 最上位の DOM エレメントに style を指定する -->
    <div aura:id="container" style="{!'height:' + v.height + 'px;'}">
        <div>高さ: {!v.height}px</div>
    </div>

</aura:component>
FixedAspectRatioHelper.js
({
    resize : function(c, h) {
        const ratio = c.get("v.ratio");
        const width = c.find("container").getElement().clientWidth;
        c.set("v.height", width * ratio);
    },
})
FixedAspectRatioRenderer.js
({
    afterRender: function (c, h) {
        this.superAfterRender();

        h.resize(c, h);
        window.addEventListener('resize', $A.getCallback(function (event) {
            h.resize(c, h);
        }));

        // コンソールでは左パネルの開閉時に window オブジェクトのリサイズイベントが発火しないので、タイマーを仕掛ける事もできる。
        // その際は、監視対象のエレメントが存在するか必ず確認する。
        let prevWidth = 0;
        const resizeTimer = setInterval($A.getCallback(function(){
            if (c.find("container")){ // 監視対象のエレメントが存在するか確認
                const curWidth = c.find("container").getElement().clientWidth;
                if (prevWidth !== curWidth) {
                    c.set("v.height", curWidth * c.get("v.ratio"));
                }
            } else {
                clearInterval(resizeTimer);
            }
        }), 500);
    },
})

・・・イイじゃん、コレで!!!!!!

気をつけたいポイント

今回のコンポーネント作成において気をつけたのは以下の 2 つです。

① javascript による直接的な DOM の変更を避ける

  • 上のコードでは、height 変数を作成して style 属性で利用しています。height はヘルパー関数から値を set(...) する事で、DOM の操作を避けています。
  • これとは別に javascript から element.style.height に値を直接代入する事も出来ます。しかし、稀に Lightining コンポーネントのレンダリングサイクルに思わぬ影響を及ぼす場合があるのでオススメしません。

② DOM が有効になってからリサイズ処理を行う

  • getElement(...) などで DOM にアクセスする必要がある際は、DOM が有効(描画が完了している)かを確認する必要があります。DOM の準備が整っていないと getElement(...)undefined に対して実行されるためエラーとなります。
  • afterRender(...) は DOM の描画が完了した時に呼ばれる関数なので、この中での DOM アクセスは安全です。そのため、リサイズ処理は、カスタムレンダラとして拡張した afterRender の中で実行します。
  • カスタムレンダラについてはこちら: カスタムレンダラの作成