iT邦幫忙

2023 iThome 鐵人賽

DAY 28
0
自我挑戰組

從零開始Vue(View)系列 第 28

[Day28]製作「活動報名表單」

  • 分享至 

  • xImage
  •  

搭配昨天的雙向綁定的學習以及之前所學的內容,製作一個簡單活動報名表單。
目標:可以讓使用者輸入姓名、電話、email以及選擇(複選)想要參加的活動。

  • 姓名輸入元件
    NameInput.vue
<template>
  <div>
    <label for="name">姓名:</label>
    <input type="text" id="name" :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" required>
  </div>
</template>

<script>
export default {
  props: ['modelValue'],
  computed: {
      name: {
        get() {
            return this.modelValue;
        },
        set(value) {
            this.$emit('update:modelValue', value);
        }
      }
  }
};
</script>
  • 電話輸入元件
    PhoneInput.vue
<template>
  <div>
    <label for="phone">電話:</label>
    <input type="tel" id="phone" :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" required>
  </div>
</template>

<script>
export default {
  props: ['modelValue'],
  computed: {
      phone: {
        get() {
            return this.modelValue;
        },
        set(value) {
            this.$emit('update:modelValue', value);
        }
      }
  }
};
</script>
  • Email輸入元件
    EmailInput.vue
<template>
  <div>
    <label for="email">Email:</label>
    <input type="email" id="email" :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" required>
  </div>
</template>

<script>
export default {
  props: ['modelValue'],
  computed: {
      email: {
        get() {
            return this.modelValue;
        },
        set(value) {
            this.$emit('update:modelValue', value);
        }
      }
  }
};
</script>
  • 活動選擇元件
    ActivityInput.vue
<template>
  <div>
    <label>選擇報名活動:</label>
    <input type="checkbox" value="游泳" v-model="localValue"> 游泳
    <input type="checkbox" value="羽球" v-model="localValue"> 羽球
    <input type="checkbox" value="排球" v-model="localValue"> 排球
    <input type="checkbox" value="籃球" v-model="localValue"> 籃球
    <input type="checkbox" value="腳踏車" v-model="localValue"> 腳踏車
  </div>
</template>

<script>
export default {
  props: ['modelValue'],
  data() {
    return {
      localValue: this.modelValue
    };
  },
  computed: {
    activity: {
       get() {
          return this.modelValue;
       },
       set(value) {
          this.$emit('update:modelValue', value);
       }
    }
  },
  watch: {
    localValue(newValue) {
      this.$emit('update:modelValue', newValue);
    }
  }
};
</script>
  • 報名表單
    EventRegistration.vue
<template>
  <form @submit.prevent="submitForm">
    <h1>活動報名</h1>
    <NameInput v-model="formData.name"></NameInput>
    <PhoneInput v-model="formData.phone"></PhoneInput>
    <EmailInput v-model="formData.email"></EmailInput>
    <ActivityInput v-model="formData.activity" @update:modelValue="updateActivity"></ActivityInput>
    <button type="submit">提交</button>
  </form>

  <div v-if="isSubmitted">
    <h2>已報名信息:</h2>
    <p>姓名: {{ formData.name }}</p>
    <p>Email: {{ formData.email }}</p>
    <p>電話: {{ formData.phone }}</p>
    <p>報名活動: {{ formData.activity.join(', ') }}</p>
  </div>
</template>

<script>
import NameInput from './NameInput.vue';
import PhoneInput from './PhoneInput.vue';
import EmailInput from './EmailInput.vue';
import ActivityInput from './ActivityInput.vue';

export default {
  data() {
    return {
      formData: {
        name: '',
        phone: '',
        email: '',
        activity: []
      },
      isSubmitted: false
    };
  },
  methods: {
    submitForm() {
      alert('報名成功!');
      this.isSubmitted = true;
    },
    updateActivity(newValue) {
      this.formData.activity = newValue;
    }
  },
  components: {
    NameInput,
    PhoneInput,
    EmailInput,
    ActivityInput
  }
};
</script>
  • html
    <div id="app">
        <event-registration></event-registration>
    </div>
    <script>
        var app = Vue.createApp({});
        var vm = app.mount('#app');
        import EventRegistration from './EventRegistration.vue';
        app.component('event-registration', EventRegistration);

        app.mount('#app');
    </script>

說明:
子元件:

  1. 姓名:
    接受一個名字為modelValue的prop,用來顯示當前的姓名值,並通過@input事件將輸入的新值傳送給父元件。
    computed:裡面有get和set方法。當讀取name屬性時,get方法會回傳modelValue的值,而當更新name屬性時,set方法會觸發update:modelValue事件,將新的值傳遞給父元件,這樣就達成了雙向綁定。

  2. 電話:同姓名元件

  3. Email:同性名元件

  4. 活動選項:
    大部分同姓名元件,但它還有一個watch來監聽本地值的變化,並將編化傳遞給父元件。這樣做是因為複選的選定狀態(選中或取消選中)不會直接更新到 modelValue中。而是會在localValue中進行追蹤。

父元件(主活動報名EventRegistration):
把主活動報名(EventRegistration)設定成父元件,裡面有一個表單(formData),其中有四個子元件:NameInput、PhoneInput、EmailInput 和 ActivityInput,還有一個isSubmitted,用來確認表單使否提交。
使用methods裡的submitForm方法提交表單,如果提交,對話框顯示"成功",並把isSubmitted設為true。
updateActivity方法則是用來從ActivityInput元件接收更新的資料,並且存到formData.activity。

使用v-model綁定formData裡的資料,並用v-if判斷,如果有提交,就顯示、更新對應的資料。報名活動的顯示、更新為formData.activity.join(', '),意思是因為我們選項是用陣列儲存,若要把陣列中的字串連在一起,就可以用join來加入,而","是將每組字串分開來,更容易閱讀。


上一篇
[Day27]元件資料的雙向綁定
下一篇
[Day29]元件客製化區域
系列文
從零開始Vue(View)30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言