# 來重構吧!-ip位址設定輸入欄(Vue) ###### tags: `來重構吧-vue` ### 前言 上一次製作出來的元件,感謝哈囉的建議讓我的code可以更精簡。 > [上一次的筆記](https://hackmd.io/_8G6GZ3kTvqUtj5E1BM7uA?both) > > [哈囉提供的建議pr](https://github.com/alphatero/components-by-vue/pull/1#pullrequestreview-908022062) 所以我們就來動手重構吧! ## 重構起來 重構分了幾個步驟 1. 元件的簡化 2. 變更數值監聽方式 3. 驗證方式 4. 使用formdata做提交 ### 元件的簡化 在原本的寫法裡,運用大量的props以及emits來做父子之間的溝通,看起來會格外的笨重。 因此簡化成,input元件只會做接收props的顯示不做其他事情。 ```javascript= //component <script setup> import { defineProps } from "vue"; defineProps({ name: Number, }); </script> <template> <input type="text" class="h-full w-full rounded-md border border-gray-300 p-1 text-center md:w-20" maxlength="3" :name="name" /> </template> //parent <div class="flex space-x-3" v-for="index in 4" :key="index"> <IpsetInput :name="index - 1" /> <label v-if="index !== 4" class="self-end">.</label> </div> ``` ### 變更數值監聽方式 原本我們利用了vue的 watch來做每個v-model的監聽,不過其實在input產生變化時去判斷target也就不用每一個input切出一個v-model去做監聽看起來很冗長。 在這裏我們首先利用了vue的一個method來監聽input行為。 ```javascript= @input="onChange" ``` 在這個**onChange**的function,首先我們取得我們想知道的幾個值,就是他的value,長度maxlength以及name。 ```javascript= function onChange(e) { const { value, maxLength, name } = e.target; } ``` 接著,因為我們希望是在input的位數到達最大位數三位的時候做判斷,所以要是沒有達到這個長度的值我們就不會去做特別處理。 ```javascript= function onChange(e) { const { value, maxLength, name } = e.target; if (value.length !== maxLength && value.length !== 0) return; } ``` 接著我們一樣想要操控DOM來讓我們輸入可以自動跳至下一個input或者在減少的時候跳回前一個input。 在這裡我們先抓到form這個element,使用的是 **.closest()** 這個方法,他可以抓到最接近你本身然後符合條件的element。 ```javascript= function onChange(e) { const { value, maxLength, name } = e.target; if (value.length !== maxLength && value.length !== 0) return; const form = e.target.closest("form"); } ``` 再來我們找到目前所在的是第幾個input,先前我們利用了name作為索引。 ```javascript= function onChange(e) { const { value, maxLength, name } = e.target; if (value.length !== maxLength && value.length !== 0) return; const form = e.target.closest("form"); const current = Number(name); } </script> ``` 接著判斷如何去跳轉input,這邊因為還要包含跳回前一個,所以我這邊做了一個自己的方法。 ```javascript= if (value.length === 0) { if (current - 1 >= 0) form.querySelector(`input[name="${current - 1}"]`)?.focus(); return; } form.querySelector(`input[name="${current + 1}"]`)?.focus(); ``` 想法是,當input不是空的時候就會跳到下一個,當是空得時候判斷他是否是第一個假如是的話不做事情,不然就會退回前一個。 ### 驗證方式 原本是使用比較暴力的去判斷他是否是數字以及在0-255之間,不過在哈囉的建議下才發現最好用的是正規表達去判斷,這邊我找到了一個判斷ip address的正規表達式(還是不會自己寫出來QAQ) ```javascript= function isValidateIP(val) { return /(\b25[0-5]|\b2[0-4][0-9]|\b[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}/.test( val ); } ``` 那麼在驗證之前,先來把四個input結合成一個ip位址吧! ### 使用formdata做提交 這邊就利用formdata來處理收到的input。 首先去建立一個FormData並且把他整理成一個只有input值的Object ```javascript= function toFormData(form) { return Object.fromEntries(new FormData(form).entries()); } ``` 這個方法很好用!出來的會是一個Object ```javascript= {0: '', 1: '', 2: '', 3: ''} ``` 接著就能把他組成一個array然後變成我們要的ip address的 string ```javascript= function onSubmit(e) { const ip = Array.from({ ...toFormData(e.target), length: 4 }).join("."); isError.value = !isValidateIP(ip); } ``` 這樣的ip就會是 ![](https://i.imgur.com/PdpW6BY.png) 簡直太棒拉! 這樣我們就能用已經設定好的驗證function就完成了呀! ```javascript= function onSubmit(e) { const ip = Array.from({ ...toFormData(e.target), length: 4 }).join("."); isError.value = !isValidateIP(ip); } ``` ### 相關github以及demo [Github](https://github.com/alphatero/components-by-vue/commit/f64b6365c95dbb661538951e8f9214a5ad5334ad) [Vercel Demo](https://components-by-vue.vercel.app/)