ログインフォームを作る3
前回、作るべきログインフォームをSketchを使って作成しました。今回は、あの画面をSencha Ext JS内で実装していきます。
toolkitについて
まず、Sencha Cmdが作成したディレクトリ構成を見ていきましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
. ├── Readme.md ├── app ├── app.js ├── app.json ├── bootstrap.css ├── bootstrap.js ├── build.xml ├── classic ├── classic.json ├── index.html ├── modern ├── modern.json ├── overrides ├── resources └── sass |
Sencha Ext JS 5まで利用した人はmodern、classicってディレクトリ増えてるけど、なんだ?と思うでしょう。Sencha Ext JS 6からtoolkitという仕組みがあり、こいつがSencha Touchとの統合を果たしたポイントとなります。
toolkitに関しては、別途詳しく説明する回を設けます。今回は簡単になんとなく理解してもらえればOKです。classic toolkit は、いままでのSencha Ext JSコンポーネントが、modern toolkitはSencha Tocuhのコンポーネントが含まれます。正確には同じもではなくmodernとして進化していますが、classc=いままでのSencha Ext JS、modern=Sencha Touchという風に思っていて問題ありません。
Sencha Ext JS 6で作成たページにアクセスすると、PCブラウザからアクセスした場合、自動的にclassicとして表示され、スマートフォンからアクセスするとmodernに自動的に切り替わります。
おわかりでしょうか….(震え声)
「え?両方つくんの??」
ってなりますよね。
正確には、「両方作れる」と思ってください。appディレクトリは、classic/modern両方の共通部分の実装ができると思ってください。
modernを殺す
今回のログインフォームは、classicのみの実装を行います。そのうち別途toolkitの説明も終わったら、このログインフォームをmodern対応したいと思います。アクセスしたときに、modernとして判定されてもclassicの表示を行うためには、app.jsonを修正します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
"builds": { "classic": { ... }, "modern": { //"toolkit": "modern", "toolkit": "classic", "theme": "theme-triton", "sass": { // "save": "modern/sass/save.scss" } } }, |
“modern”の下の“toolkit”をclassicに変更します。こうすることで、modernと判定されてもclassicの表示が行われます。
ログインフォームパネルを作成する
前述のとおり、アプリケーションのビジネスロジックは、appディレクトリ下のファイルに記述していきます。Viewの部分をclassic下に記述していきます。もちろんmodern対応する場合は、modern下にViewを記述します。さて、Sencha Cmdによって初期アプリケーションが生成されていました。そのファイルを修正していっても良いのですが、邪魔くさいので一度消してしまっても構いません。
今回作成するファイルのapp/classicのファイル構成は、以下の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
├── app │ ├── Application.js │ ├── Readme.md │ ├── model │ │ └── Readme.md │ ├── store │ │ └── Readme.md │ └── view │ └── main │ └── MainController.js ├── classic │ ├── sass │ │ ├── etc │ │ │ └── Readme.md │ │ ├── src │ │ │ ├── Readme.md │ │ │ └── view │ │ │ └── main │ │ └── var │ │ └── Readme.md │ └── src │ └── view │ └── main │ ├── Form.js │ └── Main.js |
classic/src/view/main/Form.js を実装する
実装は、下記にあるとおりですが、その実装内容を見ていきましょう。
Login.view.main.Formクラスを作成します。クラス名は、ディレクトリ構成に合わせます。view/main/Form.jsなので、Login.view.main.Formクラスになります。フォームを作成するので、Ext.form.panelを継承するためにextendに‘Ext.form.Panel’を指定します。文字列で指定する点に注意してください。
次に、xtypeを‘mainform’に指定します。この名前はなんでもよいのですが、実際にこのフォームを配置するときに使用します。フォームのレイアウトは、itemsで行います。ここちょっと長くネストしていますが、1つずつ見ていきましょう。
最初のitems下にある、2つのオブジェクトリテラルがあります。1つ目はロゴ画像を入れる領域、2つ目は、フォームをレイアウトする領域です。この領域全体の幅は、width: 250と幅を固定にします。2つの領域を内包する外側をxtype: ‘container’と指定します、これは、Ext.container.Containerクラスのxtypeです。レイアウトを行うための一番軽量なコンテナーになります。
レイアウトの指定は、‘vbox’を指定し、alignに‘stretch’を指定します。 vboxレイアウトというレイアウトがあるのですが、containerの子供の要素(items)をどのようにレイアウトするかを指定しています。このvboxの場合、縦にレイアウトするそして、heightが指定されない限り縦に伸びます。
ロゴをいれる領域のitemsの中に、画像を配置するための、imageを指定して、srcに画像までのパスを指定します。 ロゴを入れる領域自体に、heightに210を指定していますが、これは、前述の自動で伸びる部分を210ピクセルにするように指定しています。つまり、ロゴ領域は、250×210になるようにして、フォームをレイアウトする領域は、250x[伸びきる]ようになります。
2つの領域を内包するコンテナーは、前述のとおりExt.container.Containerです、そして、defaultsにもcontainerが指定されています。これは、ロゴを入れる領域、フォームをレイアウトする領域の両方にxtypeが指定されなかった場合、xtype: ‘container’になるという設定です。
フォームをレイアウトする領域は、flex: 1、layout: ‘anchor’を指定します。今回の場合、flexを1に設定していますが、さらに縦に配置する要素が複数になる場合、伸びる割合を指定することができます。そして、レイアウトはanchorレイアウトを使用しますが、これは、フォームをレイアウトする領域のitemsの要素をanchorレイアウトでレイアウトするという指定になります。
defaultsは、先ほどと一緒で、xtypeが指定されない限り、xtype:textfieldを利用します。これは、Ext.form.field.Textクラスを指しています。textfieldには、それぞれnameを指定します、これは後でプログラムがこのフィールドの値を取得するときに、認識する名前なので必ず何か指定してください。
emptyTextは、テキストが入力されていないときに表示する文字列を指定することができます。パスワードに関しては、inputType: ‘password’とすることで、パスワード入力フィールドになります。一番下のアイテムは、xtype:buttonを指定して、Ext.button.Buttonクラスを使用します。listenersの中に、click: ‘onLogin’を指定します。これは、ボタンが押された時、onLoginを呼び出すという設定です。onLoginに関しては、この後のViewControllerで実装します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ // {{{ Login.view.main.Form /** * Login.view.main.Form * * Copyright (c) 2016 Xenophy.CO.,LTD All rights Reserved. * http://www.xenophy.com */ Ext.define('Login.view.main.Form', { // {{{ extend extend: 'Ext.form.Panel', // }}} // {{{ xtype xtype: 'mainform', // }}} // {{{ requires requires: [ ], // }}} // {{{ listeners listeners: { }, // }}} // {{{ bodyPadding bodyPadding: "20 20 20 20", // }}} // {{{ items items: [{ // xtype xtype: 'container', // width width: 250, // layout layout: { // type type: 'vbox', // align align: 'stretch' }, // defaults defaults: { // xtype xtype: 'container' }, // items items: [{ // padding padding: "20 59 20 59", // height height: 210, // items items: [{ // xtype xtype: 'image', // src src: 'resources/images/logo.png' }] }, { // flex flex: 1, // layout layout: 'anchor', // defaults defaults: { // xtype xtype: 'textfield', // anchor anchor: '100%' }, // items items: [{ // name name: 'username', // emptyText emptyText: '\uf007 メールアドレスまたはユーザーID' }, { // name name: 'password', // inputType inputType: 'password', // emptyText emptyText: '\uf023 パスワード' }, { // xtype xtype: 'button', // margin margin: "20 0 10 0", // text text: 'ログイン', // listeners listeners: { click: 'onLogin' } }] }] }] // }}} }); // }}} /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * c-hanging-comment-ender-p: nil * End: */ |
classic/src/view/main/Main.js を実装する
Formパネルを作成したので、そのFormパネルをMainに配置しましょう。Ext.view.main.Mainクラスを作成します。 基本Formパネルの時と同じなので、重複する説明は省きます。ポイントは2つです。
- reqauiresに’Login.view.main.MainController’と’Login.view.main.Form’を設定する。
- vbox/hboxレイアウトを使って、Formパネルを中央に配置する。
Login.view.main.MainController クラスは、この後作成します。Login.view.main.Formは、既に作成しましたが、このクラスを、このMainクラスで使うよっ!ということを宣言しています。
vboxレイアウトについては、簡単に説明しました、同様に横向きに伸びるhboxレイアウトというのがあります。この2つを組み合わせて中央にFormパネルを配置しています。
Formパネルの配置は、xtype: ‘mainform’と指定している部分です。これは、Login.view.main.Formクラスのxtypeで指定した名前です。上下左右に、伸縮する領域を設けて、中央にmainformを配置します。こうすることで、ブラウザのウィンドウサイズが変化したときも自動的に中央に配置されます。今回はFormパネルを使用した例として説明していますが、Senchaのドキュメントにあるように、ログインフォームをWindowで実現することも可能です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ // {{{ Login.view.main.Main /** * Login.view.main.Main * * Copyright (c) 2016 Xenophy.CO.,LTD All rights Reserved. * http://www.xenophy.com */ Ext.define('Login.view.main.Main', { // {{{ extend extend: 'Ext.container.Container', // }}} // {{{ xtype xtype: 'app-main', // }}} // {{{ requires requires: [ 'Ext.plugin.Viewport', 'Ext.window.MessageBox', 'Login.view.main.MainController', 'Login.view.main.Form' ], // }}} // {{{ layout layout: { type: 'hbox', align: 'stretch' }, // }}} // {{{ controller controller: 'main', // }}} // {{{ defaults defaults: { xtype: 'container' }, // }}} // {{{ items items: [{ // spacer flex: 1 }, { // defaults defaults: { // xtype xtype: 'container' }, // layout layout: { // type type: 'vbox', // align align: 'stretch' }, // items items: [{ // spacer flex: 1 }, { // xtype xtype: 'mainform' }, { // spacer flex: 1 }] }, { // spacer flex: 1 }] // }}} }); // }}} /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * c-hanging-comment-ender-p: nil * End: */ |
app/view/main/MainControler.js を実装する
Login.view.main.MainController というクラス名で、ViewControlerを実装します。onLoginはログインボタンが押された時の処理です。先ほどFormパネルを作成したときに、click: ‘onLogin’を指定しました。その実装がここになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ // {{{ Login.view.main.MainController /** * Login.view.main.MainController * * Copyright (c) 2016 Xenophy.CO.,LTD All rights Reserved. * http://www.xenophy.com */ Ext.define('Login.view.main.MainController', { // {{{ extend extend: 'Ext.app.ViewController', // }}} // {{{ alias alias: 'controller.main', // }}} // {{{ onLogin onLogin: function () { Ext.Msg.confirm('onLogin', 'onLoginフォームが呼び出されました。'); } // }}} }); // }}} /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * c-hanging-comment-ender-p: nil * End: */ |
Main.cssの内容をクリアする
最初に自動生成されたsassが記述されているので、以下のファイルを空にします。
login/classic/sass/src/view/main/Main.scss
実行
以下のコマンドを、loginディレクトリで実行して、http://localhost:1841/login/index.phpにアクセスしてみましょう。
1 |
sencha app watch |
上手く動きましたか?
一括生成コマンド
ここまでの環境構築+ソースコードの配置を以下のコマンドで自動生成できます。 とりあえず、動かしてみて中を見ていく場合に、ご利用ください。
1 |
curl https://raw.githubusercontent.com/xenophy/code-x/master/setup/ext601/loginform3.sh | sh -s codex |
おわりに
Sencha Ext JSのクラスを実際に書いてみました。Sencha Ext JSのクラスシステムについてや、xtypeってなに?itemsってなに?コンテナーってなんだよ。みたいな感じかも知れません。もちろん、いままでSencha Ext JSを触ってきている人であれば、非常に簡単過ぎる内容だったと思いますが、これでいいんです。とりあえず、動かしましょう。回数を重ねていく中で、これらがどういった構造で動いているのかについて解説していきます。
当たり前ですが、始めたばかりの頃は動かないと何も面白くありません。今後も、しばらくとりあえず動かすという回が続きます。追って内部構造の解説や、このログインフォーム自体も進化させていきたいと思います。