六维教程

Vue3 组件 v-model

Vue3 组件事件里做了个”受控输入组件”,子组件只负责展示和上报,数据都放在父组件。

可父组件每次要用,都得写 :value@update 两行:

<ValueInput :value="keyword" @update="keyword = $event" />

页面里输入框一多,这种两行写法又长又容易写错,能不能一行搞定?

v-model

Vue3 表单绑定讲过,原生 v-model="x":value@input 的合体。组件上也能用 v-model,把上面两行合成一行:

<ValueInput v-model="keyword" />

组件上的 v-model 等价于”一个 prop 加一个事件”,Vue 把默认名定死了,prop 叫 modelValue,事件叫 update:modelValue

展开写就是这样:

<ValueInput v-model="keyword" />

<!-- 等价于 -->
<ValueInput :modelValue="keyword" @update:modelValue="keyword = $event" />

@update:modelValue 看着陌生,其实就是自定义事件,名字按 update 加冒号加 prop 名来。

prop 叫 name,事件就叫 update:name,默认 prop 是 modelValue,事件名自然是 update:modelValue

父组件这边只剩一行,第一个问题解决,但子组件呢,那边也要跟着改吗?

defineModel

父组件一行搞定了,子组件要配合它,就得接住 modelValue 这个 prop,再把变化用 update:modelValue 报回去,两样都得手动写:

<!-- 子组件 ChildInput.vue -->
<script setup>
const props = defineProps({ modelValue: String })
const emit = defineEmits(['update:modelValue'])

const onInput = (e) => {
  emit('update:modelValue', e.target.value)
}
</script>

<template>
  <input :value="props.modelValue" @input="onInput" />
</template>

prop、事件、传参,名字一个都不能写错。

为了省事,Vue3.4 起提供 defineModel,它把”接 prop 加发事件”整个封装好,子组件里只剩一个 ref:

<!-- 子组件 ChildInput.vue -->
<script setup>
const model = defineModel()   // 一个 ref,自动对接 modelValue 和 update:modelValue

const onChange = (e) => {
  model.value = e.target.value   // 赋值,就等于向上发 update:modelValue
}
</script>

<template>
  <input :value="model" @input="onChange" />
</template>
<!-- 父组件 -->
<script setup>
import { ref } from 'vue'
import ChildInput from './components/ChildInput.vue'

const keyword = ref('')
</script>

<template>
  <ChildInput v-model="keyword" />
</template>

defineModel 返回一个 ref,读是当前值,赋值自动触发父组件更新。父子两边都只剩一行,双向绑定打通。

多个 v-model

表单通常不止一个字段,比如姓名加年龄。v-model 默认只对应一个 modelValue,想多挂几个,给它们起不同名字就行:

<!-- 子组件 -->
<script setup>
const name = defineModel('name')
const age = defineModel('age')
</script>

<template>
  <input v-model="name" placeholder="名字" />
  <input v-model="age" placeholder="年龄" />
</template>
<!-- 父组件 -->
<Child v-model:name="userName" v-model:age="userAge" />

速查卡片

场景 写法
单个双向绑定 const model = defineModel()
带默认值 defineModel({ default: '默认' })
绑定多个 defineModel('name')v-model:name
父组件使用 <Child v-model="keyword" /><Child v-model:name="n" />
本质 prop modelValue 加事件 update:modelValue
上一篇
Vue3 组件事件
下一篇
Vue3 插槽基础