JavascriptのImportとVueのコンポーネントを使えるようになってみる

これまで、Javascriptのimportを特に使わず、グローバル宣言で満足していましたし、Vueも宣言的レンダリング(双方向バインディング)で満足していたのですが、世間様では、Importやコンポーネントを使うことが当たり前になってきたので、使いこなせるように、いつも使っているテンプレート環境をアップデートします。
ついでに、いつもテンプレートの使い方を忘れるので、ここでまとめておきます。

テンプレートは以下のGitHubに上げてあります。

poruruba/express_template
https://github.com/poruruba/express_template

※たびたび機能追加しているので、ここに記載していない機能も入っている可能性大です。

#テンプレートでできること

node.jsさえインストールしてあれば、すぐにWebページのホスティングサーバ、RESTサーバ、GraphQLサーバを立ち上げられるようにしています。また、HTMLページのひな型も置いており、よく使う機能はライブラリとしてまとめておいてあります。

今回の投稿では、HTMLのひな型の使い方のまとめです。

#立ち上げ方

以下から、Code一式をダウンロードします。

poruruba/express_template
https://github.com/poruruba/express_template

```
> unzip express_template-master.zip
> cd express_template-master
> npm install
> mkdir cert
> npm run start
```


上記だけで、HTTPサーバが立ち上がります。

もし、HTTPSでも立ち上げたい場合には、certフォルダにSSL証明書ファイルを配置します。
app.js の以下の場所のファイル名を、配置したファイル名に合わせます。

```js:app.js
  var options = {
    key:  fs.readFileSync('./cert/server.key'), // 秘密鍵ファイル
    cert: fs.readFileSync('./cert/server.crt'), // SSL証明書ファイル
    ca: fs.readFileSync('./cert/JPRS_DVCA_G2_PEM.cer') //SSL中間証明書ファイル
  };
```

特に何も指定しなければ、ポート番号は、HTTPは10080、HTTPSは10443で立ち上がります。
ポート番号を変えるには、.envに以下を記載します。

```txt:.env
PORT=【HTTPのポート番号】
SPORT=【HTTPSのポート番号】
```

#静的ページの作成

```public/template``` に、静的ページのひな型がありますので、適当な名前でコピーします。この名前がURLでのパスになります。
public/test とした場合、URLは、```http://localhost:10080/test``` となります。
Vue2とBootstrap5とその他もろもろを使っています。

あとは、Vueの宣言的レンダリング(双方向バインディング)の機能を使えばたいていのことは事足ります。

たとえば、以下のように```index.html```に追記して、

```html:public/template/index.html
        <h1>Template</h1>

        {{message}}
        <button class="btn btn-primary" v-on:click="btn_clicked">Button Click</button>
```

```start.js``` の該当箇所に追記すると、

```js:public/template/js/start.js
    data: {
        message: "Hello"
    },
    computed: {
    },
    methods: {
        btn_clicked: function(){
            this.message = "World";
        }
```

ブラウザから見るとHelloと表示されて、ボタンを押すとWorldに変わります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/80c2f6c6-be6e-4d37-f145-bcdec5ccb0dd.png)

{{ }} やv-on:clickはVue、buttonやbtn btn-primaryはBootstrapの機能です。

#プログレスダイアログの表示

時間がかかる処理をするときには、処理中であることがわかるようにプログレスバーのあるダイアログを表示してあげると便利です。

5秒間プログレスダイアログを表示したのちに消してみます。

プログレスダイアログの表示
　this.progress_open(表示タイトル, backdrop = 'static');
プログレスダイアログの非表示
　this.progress_close();

```html:pubic/template/index.html
    <button class="btn btn-primary" v-on:click="progress_clicked">Progress Click</button>
```

```js:public/template/js/start.js
    methods: {
        progress_clicked: function(){
            this.progress_open("プログレス表示です。");
            setTimeout(() =>{
                this.progress_close();
            }, 5000);
        }
```

backdropには、’static’またはtrueまたはfalseが指定できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/3a0d8ac4-129e-56cc-8a19-fcdbbf5eb67d.png)

#クリップボードへのコピー＆ペースト

Javascript標準のClipboard APIを使っています。

クリップボードへのコピー
　this.clip_copy(文字列)
クリップボードからペースト
　this.clip_paste()

#モーダルダイアログ

Bootstrapを使ったモーダルダイアログです。あらかじめ使いやすいようにコンポーネントとして登録しているため、以下のように使います。

index.html にモーダルダイアログの表示内容を定義します。

```html:public/template/index.html
        <modal-dialog size="lg" id="dialog_test">
            <div slot="content">
                <div class="modal-header">
                    タイトル
                </div>
                <div class="modal-body">
                    本文
                </div>
                <div class="modal-footer">
                    <button class="btn btn-primary" v-on:click="dialog_close('#dialog_test')">閉じる</button>
                </div>
            </div>
        </modal-dialog>
```

後は、ボタン押下などの契機に、以下のように呼び出します。

```js:public/template/js/start.js
        modal_clicked: function(){
            this.dialog_open('#dialog_test');
        }
```

モーダルダイアログの表示
　this.dialog_open(‘#【ダイアログのID】’);
モーダルダイアログの非表示
　this.dialog_close(‘#【ダイアログのID】’);

 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/482b0507-a33c-7d66-664d-ed88a92a84b2.png)

#アコーディオン

Bootstrapのアコーディオン表示です。
扱いやすいようにコンポーネント化していますので、以下のように定義すればよいです。

```html:public/template/index.html
        <collapse-panel id="accordion_test" title="タイトル" collapse="true">
            <span slot="content">
                <div class="card-body">
                    本文
                </div>
            </span>
        </collapse-panel>
```

collapseをtrueにすれば、初期状態で畳んだ状態となり、falseにすれば開いた状態になります。以下のJavascriptでも動的に制御できます。

アコーディオンのオープン
　this.panal_open(‘#【アコーディオンのID】’)
アコーディオンのクローズ
　this.panal_close(‘#【アコーディオンのID】’)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/3120b1e1-f543-7302-49b8-d022ba00a37c.png)

#トーストの表示

右上に、トーストを表示させます。複数同時に表示することができ、時間がたつと消えてくれます。

this.toast_show(message, level = "success")

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/eaacc6e9-9d80-ab0d-c3e0-6dac34cfe1cf.png)

内部で以下を使わせてもらっています。

ooyun0/siiimple-toast
https://github.com/ooyun0/siiimple-toast

#Cookieを設定・取得する

Cookieの設定
　Cookies.set(‘【名前】', JSON.stringify(【設定したい値】), { expires: 365 });
Cookieの取得
　var value = Cookies.get('【名前】');

単にこちらを使わせていただいているだけです。

js-cookie/js-cookie
https://github.com/js-cookie/js-cookie/tree/latest

#URLのQueryStringとフラグメント識別子

URLに指定されたQueryStringやフラグメント識別子は、mountedで呼び出している関数```proc_load()```で処理され、変数searchsとhashsに格納されています。

・QueryString(?の後に続くパラメータ)：searchs
http://localhost:10080/test/index.html?param1=abcd の場合
searches = { param1: 'abcd' }

・フラグメント識別子(#の後に続くパラメータ)：hashs
http://localhost:10080/test/index.html#param1=abcd の場合
hashs = { param1: 'abcd' }

#Vueコンポーネント

さあ、本題である、Vueコンポーネントを追加します。

例えば、こんなコンポーネントを作ります。

```js:public/template/js/comp/comp_test.js
export default {
  mixins: [mixins_bootstrap],
  template: `
<div>
  <h2>テストコンポーネント</h2>
  {{message}}
</div>`,
  data: function () {
    return {
      message: 'Hello World',
    }
  },
  methods: {
  }
};
```

start.js に以下を追加します。

```js:public/template/js/start.js
/* add additional components */
import comp_test from './comp/comp_test.js';
vue_add_global_component('comp_test', comp_test);
```

index.htmlに以下を追加します。

```hteml:public/template/index.html
        <comp_test></comp_test>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/cb16e8f4-b1f6-dbe9-4e27-8d43f8dc5b5e.png)
 

コンポーネントに以下のMixinsを入れているので、作成するコンポーネントの中で、前の方で説明したプログレスダイアログやモーダルダイアログ、アコーディオンも使えます。

```
  mixins: [mixins_bootstrap],
```

以下も参考になるかも
　[Vueのカスタムコンポーネントで双方向データバインディングを入れてみた](https://qiita.com/poruruba/items/db22fece6be12ad59365)

# WebAPI呼び出し

WebAPI呼び出しをよく使うので、関数を作っておきました。内部でfetchを使っており、Promiseが返ります。
以下、いくつかの種類がありますが、いずれもURLに加えて、パラメータをオブジェクトで渡します。

・do_post (url, body)
　JSON/POST(application/json)呼び出しです。

・do_post_urlencoded (url, params)
　application/x-www-form-urlencoded 呼び出しです。

・do_post_formdata (url, params)
　multipart/form-data呼び出しです。

・do_get (url, qs)
　GET呼び出しです。

戻り値は、JSON(application/json)を前提としているため、

```js:public/template/js/vue_utils.js
    return response.json();
```

としています。異なる場合はそれに合わせて以下のように変更してください。

```js:public/template/js/vue_utils.js
//    return response.json();
//    return response.text();
//    return response.blob();
//    return response.arrayBuffer();
```

以下も参考になるかも
　[fetchの呼び出し @Javascript & Node.js 実験室](https://qiita.com/poruruba/items/04f38662565cbeb3e746)

#GraphQL呼び出し

この呼び出しがすぐ忘れそうだったので、今回の記事をQiitaに投稿した理由です。
いろんな呼び出し方を用意したので、お好みでどうぞ。
また、X-API-Key(apikey)は、AWS Appsyncなど、必要に応じて設定してください。

```js:public/template/js/start.js
var base_url="【GraphQLのエンドポイント】";
var p1 = "Hello";
var p2 = 1234;

var templ = `query($param1: String, $param2: Int){
    hello( param1: $param1, param2: $param2){ id }
}`;
var ret = await gql_query(base_url, templ, { param1: p1, param2: p2 }, apikey);

var templ = `{
    hello(param1: \"Hello\", param2: 1234){ id }
}`;
var ret = await gql_query(base_url, templ, null, apikey);

var templ = gql_templ`{
    hello(param1: ${0}, param2: ${1}){ id }
}`;
var ret = await gql_query(base_url, templ, [p1, p2], apikey);

var templ = gql_templ`{
    hello(param1: ${0}, param2: ${1}){ id }
}`;
var ret = await gql_query(base_url, templ(p1, p2), null, apikey);
```

graqhql_requestやapolloなどいろいろあったのですが、WebPackなど使わず、Javascriptだけで手軽に使いたかったため自作し、js/gql_utils.js にまとめておきました。

#仮想コンソールの表示

スマホでの表示など、Chrome DevToolsでconsole.logなどのコンソールの出力が見えないときに使います。(Remote devicesを使う方法もありますが、それよりも手軽です)

start.js で以下の部分のコメントを外します。それだけです。

```js:public/template/js/start.js
const vConsole = new VConsole();
```
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/389d1ff2-e6a7-5f27-4e7b-15a1f3f83ce9.png)
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/15434357-7af2-83d9-3d1c-82ed43f3b792.png)

とはいっても、ただ単に、以下を使わせていただいているだけです。

Tencent/vConsole
https://github.com/Tencent/vConsole


# dat.GUIを使う

dat.GUIを表示させます。
監視対象に、Vueのデータを含められるようにしました。

dataarts/dat.gui 
https://github.com/dataarts/dat.gui

登録は以下の関数です。

　this.datgui_add(property, p1, p2, p3)

まずは、start.js の以下の部分のコメントを外します。

```js:public/template/js/start.js
window.datgui = new dat.GUI();
```

そうすると、以下のように右上に、dat.GUIが現れます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/c8a01e9b-775f-0e94-d3c4-e23c2b17dbd8.png)

例えば、このようなVueに定義を含めた場合に、

```js:public/template/js/start.js
    data: {
        message: "Hello"
    },
```

以下のように、mountedなどで、フィールド名を文字列で指定すると、dat.GUIに内容が表示されます。

```js:public/template/js/start.js
        this.datgui_add("message");
```

値が変われば自動的に右上のdat.GUIの表示も変わりますし、dat.GUIのところで値を変えれば、実際の値も変わります。
dat.GUIの仕様を参考に、p1, p2, p3も指定してみてください。

#終わりに

次回は、WebAPIの定義方法を紹介しようと思います。
 [簡単にRESTサーバ・GraphQLサーバを立ち上げる](https://qiita.com/poruruba/items/aad6a181e8ef0d956e71)

以上