---
# System prepended metadata

title: '[Vue] Custom Component 使用 v-model'
tags: [Vue, 前端筆記]

---

# [Vue] Custom Component 使用 v-model

###### tags: `Vue` `前端筆記`

## `v-model` 的基本介紹

在一般的表單 component 中，常用 `v-model` 語法糖綁定同 scope input 及 state 的值，讓開發者省略自行動態綁定 value 及傳接更動 state 的事件。

```javascript=
<template>
    <input v-model="searchText">
</template>

<script>
export default {
  data () {
      return {
          searchText: 'Lun'
      }
  }
}
</script>
```

等價於：

```javascript=
<template>
    <input
      v-bind:value="searchText"
      v-on:input="searchText = $event.target.value"
    >
</template>

<script>
export default {
  data () {
      return {
          searchText: 'Lun'
      }
  },
}
</script>
```

==所以可以得知 `v-model` 是 `:value` + `event` 縮寫的語法糖。==

## `v-model` 也可以下在 component 上，透過 `v-model` 的語法糖幫忙簡化更動 parent component state 的方法
 
==切記心法：`v-model` 是 `:value` + `event` 的縮寫語法糖。==

```javascript=
// App.vue

<template>
    <input-component v-model="name"></input-component>
</template>

<script>
import InputComponent from "./InputComponent.vue";


export default {
  name: 'APP',
  components: {
      InputComponent,
  },
  data () {
      return {
          name: 'Lun'
      }
  }
}
</script>
```

```javascript=
// InputComponent.vue

<template>
    <input type="text" :value="name" @input="$emit('input', $event.target.value)">
</template>

<script>
export default {
  name: 'InputComponent',
  // props 告訴 Vue 要往外找接來的資料，此例子是 v-model
  props: ['name']
}
</script>
```

因為 `v-model` 是 `:value` + `event` 的縮寫語法糖，所以在 child component 透過 `props` 讓 Vue 得知有外部資料，再手動綁定 `:value` 及 `event`。`evnet` 則因為 child component 要改 parent component 的 state 要透過發射事件（`$evnet`）。

> 手動綁定事件 + `$emit` = 還是「合法地」透過事件改變 parent component 的 state。

（初始化，`App.vue` 及 `TestInput.vue` state 相同）
![](https://i.imgur.com/FsGMX9S.png)
（`TestInput.vue` 輸入新值了，好險有 `v-model` 同步更新 parent 及 child 的 state）
![](https://i.imgur.com/NMpmdWF.png)
![](https://i.imgur.com/heC207K.png)


## Parent 還需要透過自己的事件接 child component 射來的 `$emit` 嗎？

不用，只要在 child component 寫入手動綁定（`props`, `:value` 及 `$emit`），在 parent component 中叫用 child component 寫入 `v-model="keyName"` 即可。

**`v-model="keyName"` -> child component props 要接的 keyName。**

## Vue 3 的大躍進

在 Vue 3 中使用 v-model to custom component 有新的 defaul keyName，讓程式碼的閱讀性更上一層樓。

```javascript=
// App.vue

<template>
    <input-component v-model="testValue"></input-component>
</template>

<script>
export default {
data () {
    return {
        testValue: 'Lun'
    }
}
}
</script>
```

```javascript=
// InputComponent.vue

<template>
    <input :value="modelValue" @input="$emit('updata:modelValue', $event.target.value)" />
</template>

<script>
export default {
// props 告訴 Vue 有外部的資料，Vue 會自己找來源
// modelValue -> 預設的 v-model keyName
props: {
    modelValue: {
        type: String
        }
    }
}
</script>
```

在 Vue 3 提供了預設的 `modelValue` 供開發者使用預設的 keyName 取得 parent 傳的 v-model 資料。
而更新資料的 `emit`，Vue 3 也有語意更明確的 `update:modelValue` 的方法，讓開發者更明白這個是更新 parent state。

（parent 透過 v-model 與 child 雙向綁定）
![](https://i.imgur.com/KIBibwj.png)

（Vue 3 預設的 `modelValue` 以及 `update:modelValue`）
![](https://i.imgur.com/jGdiMUr.png)

（多虧 v-model 雙向綁定，parent 跟 child 的 state 都有同步更新）
![](https://i.imgur.com/oTEZ5tj.png)
![](https://i.imgur.com/AAlhP12.png)

### 除了預設 `modelValue` 及 `update:modelValue` 外，開發者可以自行命名

從上部分可以得知，child 中是透過 props 預設的 `modelValue` 接 parent 的 v-model 綁定資料。
但是開發者也可以自行命名，做法很簡單，就把 parent 給 child 的 `v-model="valueKey"`，改寫成 `v-model:customName="valueKey"` 就好了。（連更新的 `emit` 也要使用 v-model 的名字）

```javascript=
// App.vue

<template>
    <input-component v-model:myName="testValue"></input-component>
</template>

<script>
export default {
data () {
    return {
        testValue: 'Lun'
    }
}
}
</script>
```

```javascript=
// InputComponent.vue

<template>
    <input :value="myName" @input="$emit('updata:myName', $event.target.value)" />
</template>

<script>
export default {
// props 告訴 Vue 有外部的資料，Vue 會自己找來源
// 因為 parent 有給名字，所以就要使用名字
props: {
   myName : {
        type: String
        }
    }
}
</script>
```

（parent 中的 state）
![](https://i.imgur.com/ihq0lAu.png)

（因為 v-model 有給名字，所以 child 也需要使用名字）-> 在開發者工具也可以看到有名字的 `props` 及 `updata:customName`
![](https://i.imgur.com/MabDkbX.png)

（child 跟 parent 都有綁在一起）
![](https://i.imgur.com/rNJI2Vs.png)
![](https://i.imgur.com/smXtADH.png)

## 參考資料
1. [Using v-model on Components](https://v2.vuejs.org/v2/guide/components.html#Using-v-model-on-Components)
2. [How To Add v-model Support to Custom Vue.js Components](https://www.digitalocean.com/community/tutorials/how-to-add-v-model-support-to-custom-vue-js-components)
3. [Vue.js Tip #1: Use V-Model on Custom Components](https://javascript.plainenglish.io/vue-js-tip-1-use-v-model-on-custom-components-be56401727e0)
4. [Vue JS 3 Tutorial - 36 - Components and v-model](https://www.youtube.com/watch?v=CALrQCw41dI)
5. [VueJS. v-model in custom component](https://stackoverflow.com/questions/46258763/vuejs-v-model-in-custom-component)
6. [008 天絕對看不完的 Vue.js 3 指南 - 2.2.7 v-model 與元件的雙向綁定](P.121 - P.122)
7. [Vue - The Complete Guide (incl. Router & Composition API) - lecture: 147](https://www.udemy.com/course/vuejs-2-the-complete-guide/learn/lecture/21526418#questions)