Vue3$Data-V-Model

103 阅读1分钟

Vue3$Data-V-Model

0. What is v-model

对于 inputselect 等 form 组件,我们希望数据能够双向绑定:初始值决定 value,同时页面上 value 的改变引起数据。 和 input 类似,传给组件的值也可以双向绑定。

我们知道 props 是单向数据流,为的是子组件不更改父组件的数据。而 v-model 是双向绑定,“双向数据流”,好像是破坏了 props 的美好设想:数据的更改操作可以在多个地方(父子组件)。

还是以抄作业为例。父组件把作业给子组件抄:

  • 多数情况下我们不希望子组件修改我们的答案,你不想这些“差生”改你的答案
  • 一些情况,你希望子组件修改你的答案,比如有道题你没做,或者只写了解题思路。你想让那个“好学生”来做

从组件本身来考虑:

  • 子组件如果只是想用外部数据,使用 props 就好
  • 子组件如果想帮父组件做点事(修改数据),使用 v-model

v-model 其实是语法糖。它使用了 props 来接收数据,同时当数据更改时 emit 了更新事件。

<!-- Child.vue -->
<script setup>
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
</script>

<template>
  <input
    :value="props.modelValue"
    @input="emit('update:modelValue', $event.target.value)"
  />
</template>
<!-- Parent.vue -->
<Child
  :modelValue="foo"
  @update:modelValue="$event => (foo = $event)"
/>

1. How to Use v-model

基本使用

<!-- Child.vue -->
<script setup>
const model = defineModel()

function update() {
  model.value++
}
</script>

<template>
  <div>Parent bound v-model is: {{ model }}</div>
  <button @click="update">increase</button>
</template>
<!-- Parent.vue -->
<Child v-model="modelCount" />

参数(用于区分多个数据)

<MyComponent v-model:title="bookTitle" v-model:name="Tom" />
<!-- MyComponent.vue -->
<script setup>
const title = defineModel('title')
// const title = defineModel('title', { required: true })
const name = defineModel('name)
</script>

<template>
  <input type="text" v-model="title" />
  <input type="text" v-model="name" />
</template>

限制 Options

// making the v-model required
const model = defineModel({ required: true })

// providing a default value
const model = defineModel({ default: 0 })

修饰符

  1. 普通 form 修饰符:.trim, .nnumber, .lazy
  2. 组件自定义修饰符
<MyComponent v-model.capitalize="myText" />
<script setup>
const [model, modifiers] = defineModel()
console.log(modifiers) // { capitalize: true }
</script>

<template>
  <input type="text" v-model="model" />
</template>
<script setup>
const [model, modifiers] = defineModel({
  set(value) {
    if (modifiers.capitalize) {
      return value.charAt(0).toUpperCase() + value.slice(1)
    }
    return value
  }
})
</script>

<template>
  <input type="text" v-model="model" />
</template>

Links

VueVModel