Vue.js v2でフォームを作成する

2021年4月14日Vue.js

Vue.jsでフォームを作成する方法をみていきましょう。

composition APIでのフォームの作成方法は次の記事を参考にしてみてください。

Vue.jsでフォームを作成する

親コンポーネントApp.vueと子コンポーネントSignupForm.vueを作成します。

親コンポーネントApp.vue

<template> 
  <SignupFrom/>
</template>
<script>
import SignupFrom from './components/SignupForm';

export default {
  name: 'App',
  components: { SignupFrom }
};
</script>
<style scoped>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
body {
  margin: 0;
  background-color: #eee;
}
</style>

v-modelを使うことで双方向 (two-way) データバインディングを作成できます。
入力した文字をリアルタイムで取得・表示することができます。

子コンポーネントSignupForm.vue

<template>
  <!-- .preventをつけて送信したときにブラウザ遷移しないようにする -->
  <form @submit.prevent="handleSubmit">
    <label>Email: </label>
    <!-- v-modelを使うことで双方向 (two-way) データバインディングを作成できる -->
    <input type="email" required v-model="email" />

    <label>Password: </label>
    <input type="password" required v-model="password" />
    <div v-if="passwordError" class="error">{{ passwordError }}</div>

    <label>Role:</label>
    <select v-model="role">
      <option value="frontend">フロントエンド開発者</option>
      <option value="backend">バックエンド開発者</option>
      <option value="designer">Webデザイナー</option>
    </select>

    <!-- <label>スキル:</label>
    <input type="text" v-model="tempSkill" @keyup="addSkill" />
    <div v-for="skill in skills" :key="skill" class="pill">
      <span @click="deleteSkill(skill)">{{ skill }}</span>
    </div> -->

    <label>Skills (ctrl + コンマで追加):</label>
    <input type="text" v-model="tempSkill" @keyup.ctrl="addSkill">
    <div v-for="skill in skills" :key="skill" class="pill">
      <span @click="deleteSkill(skill)">{{ skill }}</span>
    </div>

    <div class="terms">
      <input type="checkbox" v-model="terms" required />
      <label>以下内容を確認しました。</label>
    </div>

    <h4>チェックボックス複数選択</h4>
    <div>
      <input type="checkbox" value="name1" v-model="names" />
      <label>名前1</label>
    </div>
    <div>
      <input type="checkbox" value="name2" v-model="names" />
      <label>名前2</label>
    </div>
    <div>
      <input type="checkbox" value="name3" v-model="names" />
      <label>名前3</label>
    </div>

    <div class="submit">
      <button>アカウントを作成</button>
    </div>
  </form>
  <!-- v-modelなので入力したと同時に出力が確認できる -->
  <!-- selectボックスでは選択したもののvalue値が確認できる -->
  <!-- <p>Email: {{ email }}</p> -->
  <!-- <p>Password: {{ password }}</p> -->
  <!-- <p>Role: {{ role }}</p>  -->
  <!-- <p>Terms accepted: {{ terms }}</p> -->
  <!-- <p>Name: {{ names }}</p> -->
</template>
<script>
export default {
  data() {
    return {
      email: '',
      password: '',
      role: 'frontend', // デフォルトが空がいいなら''でOK
      terms: false, //デフォルトで✓がないほうがいい場合false
      names: [], //複数選択する可能性があるので配列にしておく
      tempSkill: '',
      skills: [],
      passwordError: ''
    };
  },
  methods: {
    addSkill($event) {
      // ,が打たれるかつ空白で,を打っていない場合
      if($event.key === ',' && this.tempSkill) {
        // 重複を避けるif
        if (!this.skills.includes(this.tempSkill)) {
          this.skills.push(this.tempSkill); //tempSkillをskillsの配列に格納する
        }
        this.tempSkill = '';
      }
    },
    deleteSkill(skill) {
      this.skills = this.skills.filter(item => {
        // 削除したいものが引数skillに渡される。のでそれと異なる場合deleteしないのでfilterを通す
        return skill !== item;
        // deleteしたいskillがないfilterした配列が返るので結果として削除している
      });
    },
    handleSubmit() {
      // console.log('フォームが送信されました');
      // validate password
      this.passwordError =
        this.password.length > 5
          ? ''
          : 'パスワードは6文字以上入力してください。';
        if(!this.passwordError) {
          console.log('email:', this.email);
          console.log('password:', this.password);
          console.log('role:', this.role);
          console.log('skills:', this.skills);
          console.log('確認しました', this.terms);
        }
    }
  }
};
</script>

@keyupの部分は、@keydown.enter.preventとすれば、enterを押すと追加する仕様にできます。

<style scoped>
form {
  max-width: 420px;
  margin: 30px auto;
  background-color: white;
  text-align: left;
  padding: 40px;
  border-radius: 10px;
}
label {
  color: #aaa;
  display: inline-block;
  margin: 25px 0 15px;
  font-size: 0.6em;
  text-transform: uppercase;
  letter-spacing: 1px;
  font-weight: bold;
}
input,
select {
  display: block;
  padding: 10px 6px;
  width: 100%;
  box-sizing: border-box;
  border: none;
  border-bottom: 1px solid #ddd;
  color: #555;
}
input[type='checkbox'] {
  display: inline-block;
  width: 16px;
  margin: 0 10px 0 0;
  position: relative;
  top: 2px;
}
h4 {
  margin-bottom: 0;
}
.pill {
  display: inline-block;
  margin: 20px 10px 0 0;
  padding: 6px 12px;
  background-color: #eee;
  border-radius: 20px;
  font-size: 12px;
  letter-spacing: 1px;
  font-weight: bold;
  color: #777;
  cursor: pointer;
}
button {
  background-color: #0b6dff;
  border: 0;
  padding: 10px 20px;
  margin-top: 20px;
  color: white;
  border-radius: 20px;
}
.submit {
  text-align: center;
}
.error {
  color: #ff0062;
  margin-top: 10px;
  font-size: 0.8em;
  font-weight: bold;
}
</style>

Vue.js

Posted by devsakaso