---
# System prepended metadata

title: 來重構吧！-ip位址設定輸入欄（Vue）
tags: [來重構吧-vue]

---

# 來重構吧！-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/)