Skip to content

组件 v-model(组件输入绑定)

拆解

v-model -> v-model:modelValue -> :modelValue + @update:modelValue

基本用法

父组件

vue
<Child v-model="model" />

子组件

ts
// Ref<string | undefined>
// const modelValue = defineModel<string>()

// Ref<string>
const modelValue = defineModel<string>({ required: true })
ts
interface Props {
  // modelValue?: string
  modelValue: string
}
interface Emits {
  'update:modelValue': [value: string]
}

const props = defineProps<Props>()
const emit = defineEmits<Emits>()

多个 v-model 绑定

父组件

template
<UserName
  v-model:first-name="first"
  v-model:last-name="last"
/>

子组件

js
const first = defineModel('firstName')
const last = defineModel('lastName')
js
defineProps({
  firstName: String,
  lastName: String,
})

defineEmits(['update:firstName', 'update:lastName'])

v-model 的修饰符

v-model.capitalize

父组件

template
<MyComponent v-model.capitalize="myText" />

子组件

ts
const [model, modifiers] = defineModel<string, 'capitalize'>({
  get(value: string) {
    return value
  },
  set(value: string) {
    if (modifiers.capitalize) {
      return value.charAt(0).toUpperCase() + value.slice(1)
    }
    return value
  },
})
ts
interface Props {
  modelValue: string
  modelModifiers?: {
    capitalize?: boolean
  }
}
interface Emits {
  'update:modelValue': [value: string]
}

const props = defineProps<Props>()
const emit = defineEmits<Emits>()

const model = computed({
  get: () => props.modelValue,
  set: (val: string) => {
    let value = val
    if (props.modelModifiers?.capitalize) {
      value = val.charAt(0).toUpperCase() + val.slice(1)
    }
    emit('update:modelValue', value)
  },
})

v-model:msg.capitalize

父组件

template
<MyComponent v-model:msg.capitalize="myText" />

子组件

ts
const [msg, modifiers] = defineModel<string, 'capitalize'>('msg', {
  get(value: string) {
    return value
  },
  set(value: string) {
    if (modifiers.capitalize) {
      return value.charAt(0).toUpperCase() + value.slice(1)
    }
    return value
  },
})
ts
interface Props {
  msg: string
  msgModifiers?: {
    capitalize?: boolean
  }
}
interface Emits {
  'update:msg': [value: string]
}
const props = defineProps<Props>()
const emit = defineEmits<Emits>()

const msg = computed({
  get: () => props.msg,
  set: (val: string) => {
    let value = val
    if (props.msgModifiers?.capitalize) {
      value = val.charAt(0).toUpperCase() + val.slice(1)
    }
    emit('update:msg', value)
  },
})

开发技巧

v-model 优雅继承

vue
<script setup lang="ts">
import { computed } from 'vue'

const props = defineProps<{
  firstName: string
  lastName: string
}>()
const emit = defineEmits<{
  'update:firstName': [value: string]
  'update:lastName': [value: string]
}>()

// 实现响应式的 computed
const first = computed({
  get: () => props.firstName,
  set: (val: string) => emit('update:firstName', val),
})

const last = computed({
  get: () => props.lastName,
  set: (val: string) => emit('update:lastName', val),
})
</script>

<template>
  <input v-model="first" />
  <input v-model="last" />
</template>
vue
<script setup lang="ts">
interface Props {
  firstName: string
  lastName: string
}
interface Emits {
  'update:firstName': [value: string]
  'update:lastName': [value: string]
}

const props = defineProps<Props>()
const emit = defineEmits<Emits>()

// 处理 firstName
function onFirstInput(e: Event) {
  const value = (e.target as HTMLInputElement).value
  emit('update:firstName', value)
}

// 处理 lastName
function onLastInput(e: Event) {
  const value = (e.target as HTMLInputElement).value
  emit('update:lastName', value)
}
</script>

<template>
  <a-input :value="props.firstName" @input="onFirstInput" />
  <a-input :value="props.lastName" @input="onLastInput" />
</template>

基于 MIT 许可发布