【JavaScript】ElementUIのFormComponentを使用したフォームでリクエスト送信時、二重送信されないように画面をロックさせる


# フォーム送信時はユーザーに操作させたくない

フォームの送信ボタンを押したときは二重にリクエストが飛ばないように**ボタンを押せなくした**り、そもそも**画面の項目に触れてほしくない**ので**画面をロック状態にするようにしたい**

以下は過去行ってた二重送信対応策（jQuery）
[【JavaScript】フォーム等の送信ボタンに対する二重送信防止対応策 - Qiita](https://qiita.com/sola-msr/items/1b5b3f1c0f64e73f73af)

# ElementUIのコンポーネントたちを使用して実現させる

今回は[ElementUI](https://element.eleme.io/#/en-US)（Vue.jsのコンポーネントライブラリ）の[Formコンポーネント](https://element.eleme.io/#/en-US/component/form)と[loadingコンポーネント](https://element.eleme.io/#/en-US/component/loading)を組み合わせて、**フォームのリクエスト送信時に画面をロックさせる**

# サンプル

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="html,result" data-user="sola-msr" data-slug-hash="WNwJpmq" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Lock screen when sending By ElementUI">
  <span>See the Pen <a href="https://codepen.io/sola-msr/pen/WNwJpmq">
  Lock screen when sending By ElementUI</a> by sola-msr (<a href="https://codepen.io/sola-msr">@sola-msr</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

# 対応部分

サンプルでは**`v-loading.fullscreen.lock`**をボタン部分に追加し、**送信時にローディング描写をON（`true`）、送信完了（正常系レスポンス受け取り時）にOFF（`false`）をセット**しています。
上記の対応だけではまだ**送信ボタンを押下することが出来る状態**ですので、追加の対応として**フォーム全体を非活性化（`disabled`）**させるように、**`el-form`部分に`disabled`を追加**し、これも**送信時と送信完了時にON/OFFさせる**ようにしています。

```vue
<el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="120px" class="demo-ruleForm" :disabled="this.disabledForm">
  <el-form-item label="Name" prop="name">
    <el-input type="text" v-model="ruleForm.name" autocomplete="off"></el-input>
  </el-form-item>
  <el-form-item label="Password" prop="pass">
    <el-input type="password" v-model="ruleForm.pass" autocomplete="off"></el-input>
  </el-form-item>
  <el-form-item label="Confirm" prop="checkPass">
    <el-input type="password" v-model="ruleForm.checkPass" autocomplete="off"></el-input>
  </el-form-item>
    <el-form-item label="Activity zone" prop="region">
    <el-select v-model="ruleForm.region" placeholder="Activity zone">
      <el-option label="Zone one" value="shanghai"></el-option>
      <el-option label="Zone two" value="beijing"></el-option>
    </el-select>
  </el-form-item>

  <el-form-item>
    <el-button type="primary" @click="submitForm('ruleForm')" v-loading.fullscreen.lock="fullscreenLoading">Submit</el-button>
    <el-button @click="resetForm('ruleForm')">Reset</el-button>
  </el-form-item>
</el-form>
```

`methods`で変数**`fullscreenLoading`**と**`disabledForm`**に`true`/`false`をセットする関数(**`openFullScreen()`**と**`closeFullScreen()`**)を定義し、**`submitForm`関数**の中で各々のタイミングで呼び出すようにしてます。

```js
// 略
    methods: {
      openFullScreen() {
         this.fullscreenLoading = true;
         this.disabledForm = true;
      },
      closeFullScreen() {
         this.fullscreenLoading = false;
         this.disabledForm = false;
      },
      submitForm(formName) {        
        this.$refs[formName].validate((valid) => {
          if (valid) {
            
            // ローディング描写とフォーム非活性化
            this.openFullScreen();
            
            // イメージしやすいようにあえて3秒間ローディング描写させるようにしてます
            setTimeout(() => {
              alert('submit!');
              // ローディング描写とフォーム非活性化をそれぞれ解除
              this.closeFullScreen();
            }, 3000);
            
          } else {
            // ここでもcloseFullScreen()を実行したほうがいいかもしれません
            console.log('error submit!!');
            return false;
          }
        });
      },
// 略
```

# おわり
- ローディング描写中にさらにプログレスバーを表示させる方法を知りたい（切実）

# 参考URL
- [ElementUI](https://element.eleme.io/#/en-US)
- [Formコンポーネント](https://element.eleme.io/#/en-US/component/form)
- [loadingコンポーネント](https://element.eleme.io/#/en-US/component/loading)