初心者のためのExtJS入門

ExtJSを使うので、ついでにまとめていきます

レスポンシブ対応

今回はレスポンシブ対応を試してみます。

CSSではメディアクエリを使ってレスポンシブ対応しますが、ExtJSではExt.plugin.Responsiveクラスを使いjavascript上で処理します。

ExtJSのコードをざっと見た感じでは、resizeイベント発火を起点にしているようです。

基本的な実装方法

Ext.plugin.Responsiveプラグインを使用するようにして、responsiveConfigコンフィグで状態に応じた設定を指定します。

Ext.define('Sample.view.sample.Panel', {
    extend: 'Ext.panel.Panel',
    xtype: 'sample_panel',

    requires: [
        'Ext.plugin.Responsive'
    ],

    cls: 'sample-panel',

    plugins: 'responsive',

    responsiveConfig: {
        'width < 800': {
            html: '幅が800px未満の場合のテキストを表示しています'
        },

        'width >= 800': {
            html: '幅が800px以上の場合のテキストを表示しています'
        }
    }
});

f:id:sham-memo:20170717120206p:plain

f:id:sham-memo:20170717120040p:plain

それぞれブラウザの幅が800px未満、800px以上の場合の表示です。

responsiveConfigコンフィグのキーとして、width < 800、width >= 800のように指定することで、対象コンポーネントのwidthが800px未満と800px以上という条件を指定できます。

さらにそれぞれの場合にどのような値を設定するかを、条件の値としてオブジェクトリテラルで指定できます。

responsiveConfigコンフィグの条件としては、下記の値が指定できます(http://docs.sencha.com/extjs/6.5.0/classic/Ext.mixin.Responsive.html#cfg-responsiveConfig より引用)。

landscape - True if the device orientation is landscape (always true on desktop devices).
portrait - True if the device orientation is portrait (always false on desktop devices).
tall - True if width < height regardless of device type.
wide - True if width > height regardless of device type.
width - The width of the viewport in pixels.
height - The height of the viewport in pixels.
platform - An object containing various booleans describing the platform (see Ext.platformTags). The properties of this object are also available implicitly (without "platform." prefix) but this sub-object may be useful to resolve ambiguity (for example, if one of the responsiveFormulas overlaps and hides any of these properties). Previous to Ext JS 5.1, the platformTags were only available using this prefix.

少し実用的な使い方

少し実用的な使い方だとこんな風にもできます。

ナビゲーションメニューの位置を、幅によって切り替えることを想定しています。

Ext.define('Sample.view.main.Main', {
    extend: 'Ext.panel.Panel',
    xtype: 'app-main',

    requires: [
        'Ext.plugin.Viewport',
        'Ext.plugin.Responsive',
        'Ext.layout.container.Border'
    ],

    layout: 'border',

    defaults: {
        xtype: 'panel'
    },

    items: [
        {
            xtype: 'panel',

            cls: 'menu-panel',

            plugins: 'responsive',

            responsiveConfig: {
                'width < 800': {
                    region: 'north',
                    width: '100%',
                    html: 'region: northのパネル'
                },
                'width >= 800': {
                    region: 'west',
                    width: 250,
                    html: 'region: westのパネル'
                }
            }
        },
        {
            region: 'center',
            cls: 'center-panel',
            html: 'region: centerのパネル'
        }
    ]
});

f:id:sham-memo:20170717124412p:plain

f:id:sham-memo:20170717124422p:plain

注意点

setメソッドがない場合は自分で定義する必要がある

responsiveConfigコンフィグに指定する値として、気を付けなければならない点があります。

レスポンシブの内部処理は、指定された設定値のキーに対してsetメソッドを呼び出すようになっています。

そのためsetメソッドが実装されていないコンフィグを指定した場合は、値が切り替わりません。

例えばclsコンフィグを切り替えようと、下記のようにしても反映されません。(以前はエラーになっていましたが無視されて処理継続されるようです)

responsiveConfig: {
    'width < 800': {
        region: 'north',
        cls: 'north-menu-panel',
        width: '100%'
    },
    'width >= 800': {
        region: 'west',
        cls: 'west-menu-panel',
        width: 250
    }
}

このような場合は、自分でsetメソッドを用意してあげる必要があります。

Ext.define('Sample.view.sample.Panel', {
    extend: 'Ext.panel.Panel',
    xtype: 'sample_panel',

    config: {
        /**
         * @cfg {string} 現在のレスポンシブによるセレクタ名。
         */
        currentResponsiveCls: null
    },

    /**
     * clsコンフィグのsetメソッド(レスポンシブプラグインで呼び出される)。
     * @param {string} cls セレクタ名
     */
    setCls: function (cls) {
        var me = this,
            currentCls = me.getCurrentResponsiveCls();

        if (currentCls) {
            me.removeCls(currentCls);
        }

        if (cls) {
            me.setCurrentResponsiveCls(cls);
            me.addCls(cls);
        }
    }
});

Ext.define('Sample.view.main.Main', {
    extend: 'Ext.panel.Panel',
    xtype: 'app-main',

    requires: [
        'Ext.plugin.Viewport',
        'Ext.plugin.Responsive',
        'Ext.layout.container.Border'
    ],

    layout: 'border',

    defaults: {
        xtype: 'panel'
    },

    items: [
        {
            xtype: 'sample_panel',

            plugins: 'responsive',

            html: 'ナビゲーションメニューパネル',

            responsiveConfig: {
                'width < 800': {
                    region: 'north',
                    cls: 'north-menu-panel',
                    width: '100%'
                },
                'width >= 800': {
                    region: 'west',
                    cls: 'west-menu-panel',
                    width: 250
                }
            }
        },
        {
            region: 'center',
            cls: 'content-panel',
            html: 'コンテンツパネル'
        }
    ]
});
@charset "UTF-8";

.west-menu-panel {
    .x-panel-body-default {
        background-color: #90caf9;
    }
}

.north-menu-panel {
    .x-panel-body-default {
        background-color: #80cbc4;
    }
}

.content-panel {
    .x-panel-body-default {
        background-color: #e3f2fd;
    }
}

f:id:sham-memo:20170717132744p:plain

f:id:sham-memo:20170717132755p:plain

あまりスマートな記述ではありませんが、一応期待通りになりました。

aこういうsetメソッドはプラグインとして作成したほうが良いでしょうね。

modernのプラグインの動作があやしい

バグかもしれませんが、modernのExt.plugin.Responsiveの動作が若干怪しいです。

メインビューで直接レスポンシブを指定する場合は動作しましたが、ビューをクラス定義してその中でレスポンシブ指定するとなぜか動作しませんでした。

ExtJS6.5.1に期待します。