iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 11
0
自我挑戰組

網頁前端框架 Vue 3 從頭開始(重新挑戰)系列 第 11

vue3 Composition API 學習手冊-11 監聽器

  • 分享至 

  • xImage
  •  

上一篇文章中介紹到了Vue.js裡面的計算屬性(Computed),也比較了Computed與Methods之間的差異,今天再來介紹一個跟他們也有幾許類似的監聽器(Watch),Watch主要是去監聽在Vue裡面的數據,若數據發生變化的時候,會自動去執行相對應的動作,在這邊還是一樣透過BMI計算的範例來說明Watch的運作方法:

<div id="app">
    <p>Height:<input type="number" v-model="state.height">CM</p>
    <p>Weight:<input type="number" v-model="state.weight">KG</p>
    <p>BMI: {{ state.bmi }}</p>
    <p>Suggestion:{{ state.bmiMessage }}</p>
</div>
<script>
const { reactive, watch } = Vue;
const app = {
    setup(){
        const state = reactive({
            height: 180,
            weight: 80,
            bmi: 24.69,
            bmiMessage: "過重",
        })
        watch(() => [state.height, state.weight], () =>{
            generateBMI();
        })
        function generateBMI(){
            state.bmi = (state.weight / (Math.pow((state.height / 100), 2))).toFixed(2);
            if (state.bmi > 35) {
                state.bmiMessage = "重度肥胖";
            } else if (state.bmi >= 30 && state.bmi < 35) {
                state.bmiMessage = "中度肥胖";
            } else if (state.bmi >= 27 && state.bmi < 30) {
                state.bmiMessage = "輕度肥胖";
            } else if (state.bmi >= 24 && state.bmi < 27) {
                state.bmiMessage = "過重";
            } else if (state.bmi >= 18.5 && state.bmi < 24) {
                state.bmiMessage = "正常範圍";
            } else {
                state.bmiMessage = "體重過輕";
            }
        }
        return { state };
    }
}
const myVue = Vue.createApp(app).mount("#app");
</script>

Watch在上面範例的10~12行,主要是監聽height和weight兩項數值,若數值有變化會自動觸發其中的動作,而從範例中會執行generateBMI Function。

範例檔

也許這個範例並沒有辦法感受到Watch的作用,因為這個範例同樣可以透過Computed來完成,在這邊就不示範做法了,接下來我們感受看看一些其他的Watch使用情境:

<div id="app">
    <p>用戶姓名:
        <input type="text" v-model="state.username" placeholder="請輸入5~15個小寫英文,符號僅能使用@-_" size="50">
        <span class="errorMessage">{{ state.usernameMsg }}</span>
    </p>
</div>
<script>
const { reactive, watch } = Vue;
const app = {
    setup(){
        const state = reactive({
            username: "",
            usernameMsg: "",
        })
        watch(() => state.username, (value) =>{
            state.username = state.username.replace(/[^a-zA-Z0-9_@-]/g, "");
            const usernameReg = /^.{5,15}$/;
            if (usernameReg.test(value)) {
                state.usernameMsg = "";
            } else {
                state.usernameMsg = "請輸入5~15個字以上";
            }
        })
        return { state };
    }
}
const myVue = Vue.createApp(app).mount("#app");
</script>

這個範例是一個讓使用者輸入名稱的Input Box,我們希望在輸入資料的時候,限制僅能輸入英文大小寫、數字與“@”、“_”、“-”,這三個特殊符號,只要超過上述的範圍,會讓使用者無法進行輸入,而這樣的條件剛好讓我們可以透過Watch方便的來完成。

範例檔

我們來思考一樣這樣的案例是否可以透過Computed來做?如果你還記得上一篇文章提到Computed提到的特點,就會發現上面程式中Replace那一行一定會有問題,因為他是要將值回寫到username中,而Computed還需要透過Setter來做那相對來說就麻煩很多,那Function呢?當然以上都是可行的作法,但都不如Watch來得方便,所以沒有什麼是一定要用到誰,而是透過不同的使用情境來決定!

我們把上述的範例進行一些延伸,大家也可以多多思考,有哪些案例透過Watch來處理可以達到事半功倍的效果。

<div id="app">
    <p>用戶姓名:
        <input type="text" v-model="state.username" placeholder="請輸入5~15個小寫英文,符號僅能使用@-_" size="50">
        <span class="errorMessage">{{ state.errorMessage.usernameMsg }}</span>
    </p>
    <p>電子郵件:
        <input type="text" v-model="state.email" placeholder="請輸入電子郵件" size="25">
        <span class="errorMessage">{{ state.errorMessage.emailMsg }}</span>
    </p>
    <p>登入密碼:
        <input type="text" v-model="state.password" placeholder="請輸入八個字以上,建議包含大小寫英文字母與數字" size="45">
        <span class="errorMessage">{{ state.errorMessage.passwordMsg }}</span>
    </p>
    <p>密碼確認:
        <input type="text" v-model="state.passwordConfirm" placeholder="請再輸入一次密碼" size="45">
        <span class="errorMessage">{{ state.errorMessage.passwordConfirmMsg }}</span>
    </p>
</div>
<script>
const { reactive, watch } = Vue;
const app = {
    setup(){
        const state = reactive({
            username: "",
            email: "",
            password: "",
            passwordConfirm: "",
            errorMessage: {
                usernameMsg: "",
                emailMsg: "",
                passwordMsg: "",
                passwordConfirmMsg: "",
            }
        })
        watch(() => state.username, (value) =>{
            state.username = state.username.replace(/[^a-zA-Z0-9_@-]/g, "");
            const usernameReg = /^.{5,15}$/;
            if (usernameReg.test(value)) {
                state.errorMessage.usernameMsg = "";
            } else {
                state.errorMessage.usernameMsg = "請輸入5~15個字以上";
            }
        })
        watch(() => state.email, (value) =>{
            const emailReg = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/g;
            if (emailReg.test(value)) {
                state.errorMessage.emailMsg = "";
            } else {
                state.errorMessage.emailMsg = "無效的電子郵件地址";
            }
        })
        watch(() => state.password, (value) =>{
            let passwordLV = 0;
            if (!/^.{8,}$/.test(value)) { // 八位數以上
                state.errorMessage.passwordMsg = "請輸入八個字以上的密碼";
            } else {
                if (/\d+/.test(value)) { // 包含數字
                    passwordLV++;
                }
                if (/[a-z]+/.test(value)) { // 包含小寫英文
                    passwordLV++;
                }
                if (/[A-Z]+/.test(value)) { // 包含大寫英文
                    passwordLV++;
                }
                if (passwordLV === 1) {
                    state.errorMessage.passwordMsg = "弱";
                } else if (passwordLV === 2) {
                    state.errorMessage.passwordMsg = "中";
                } else {
                    state.errorMessage.passwordMsg = "強";
                }
            }
        })
        watch(() => state.passwordConfirm, (value) =>{
            if (state.password !== value) {
                state.errorMessage.passwordConfirmMsg = "與密碼不符";
            } else {
                state.errorMessage.passwordConfirmMsg = "";
            }
        })
        return { state };
    }
}
const myVue = Vue.createApp(app).mount("#app");
</script>

範例檔

上面的案例大家也可以思考看看,如何透過其他的方法來完成,是否會比Watch更好更快?還是你已經找到Watch的特點了呢?


上一篇
vue3 Composition API 學習手冊-10 計算屬性的setter
下一篇
vue3 Composition API 學習手冊-12 實作 多層次動態選單
系列文
網頁前端框架 Vue 3 從頭開始(重新挑戰)30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言