v-model 可以在组件上使用以实现双向绑定

简单使用

  Home.vue
  
  <template>
    <Child v-model="city"></Child>
  </template>

  <script lang="ts" setup>
    import { ref } from 'vue'
    import Child from '@/views/home/Child'
    const city = ref('bj')
  </script>
  Child.vue
  
  <template>
    <input
      :value="props.modelValue"
      @input="emit('update:modelValue', $event.target.value)"
    />
  </template>

  <script lang="ts" setup>
    const props = defineProps(['modelValue'])
    const emit = defineEmits(['update:modelValue'])
  </script>

组件 v-model 等同于给子组件传递一个名为 modelValue 的prop;并接受一个名为 update:modelValue 的事件。如:

  Home.vue
  
  <template>
    <!-- <Child v-model="city"></Child> -->
    <!-- 等同于上面的 v-model="city" -->
    <Child :modelValue="city" @update:modelValue="handleCity"></Child>
  </template>

  <script lang="ts" setup>
    import { ref } from 'vue'
    import Child from '@/views/home/Child'
    const city = ref('bj')
    const handleCity = (value) => {
      city.value = value
    }
  </script>

多属性双向绑定

当子组件中一个变量需要和父组件做成同步时,此时可以通过 computed 实现

  Home.vue
  
  <template>
    <Child v-model="city" v-model:address="address"></Child>
  </template>
  
  <script lang="ts" setup>
    import { ref } from 'vue'
    import Child from '@/views/home/Child'
    const city = ref('bj')
    const address = ref('haidian')
  </script>
  Child.vue
  
  <template>
    <input v-model="localCity" />
    <input v-model="localAddress" />
  </template>

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

    type TProps = {
      modelValue: string
      address: string
    }
    const props = withDefaults(defineProps<TProps>(), {})

    const emit = defineEmits(['update:modelValue', 'update:address'])

    const localCity = computed({
      get() {
        return props.modelValue
      },
      set(value) {
        emit('update:modelValue', value)
      }
    })

    const localAddress = computed({
      get() {
        return props.address
      },
      set(value) {
        emit('update:address', value)
      }
    })
  </script>

在子组件中通过 computed 的 get 获取 prop 中的值,通过 set 再触发事件修改值

当 v-model 增加参数时,传递到子组件默认的 modelValue 就会变成 传递的参数,如:address,同时触发事件也会由 update:modelValue 变成 update:address

vueuse 库的 useVModel 内部大体也是这样实现的

defineModel 使用

Vue 3.4 开始,推荐的实现方式是使用 defineModel() 宏,这个宏可以用来声明一个双向绑定 prop,通过父组件的 v-model 来使用

defineModel() 返回的值是一个 ref。它可以像其他 ref 一样被访问以及修改,不过它能起到在父组件和当前变量之间的双向绑定的作用

  1. 它的 .value 和父组件的 v-model 的值同步;
  2. 当它被子组件变更了,会触发父组件绑定的值一起更新。

在底层,这个宏声明了一个 model prop 和一个相应的值更新事件。如果第一个参数是一个字符串字面量,它将被用作 prop 名称;否则,prop 名称将默认为 “modelValue”。在这两种情况下,你都可以再传递一个额外的对象,它可以包含 prop 的选项和 model ref 的值转换选项。

defineModel 底层编译器将其展开为以下内容:

  1. 一个名为 modelValue 的 prop,本地 ref 的值与其同步;
  2. 一个名为 update:modelValue 的事件,当本地 ref 的值发生变更时触发。

  // 声明 "modelValue" prop,由父组件通过 v-model 使用
  const model = defineModel()

  // 或者:声明带选项的 "modelValue" prop
  const model = defineModel({ type: String })
    
  // 在被修改时,触发 "update:modelValue" 事件
  model.value = "hello"
    
  // 声明 "count" prop,由父组件通过 v-model:count 使用
  const count = defineModel("count")
  // 或者:声明带选项的 "count" prop
  const count = defineModel("count", { type: Number, default: 0 })
    
  function inc() {
    // 在被修改时,触发 "update:count" 事件
    count.value++
  }

在 TypeScript 中使用

defineModel 也可以接收类型参数来指定 model 值和修饰符的类型:

  const modelValue = defineModel<string>()

  // 用带有选项的默认 model,设置 required 去掉了可能的 undefined 值
  const modelValue = defineModel<string>({ required: true })

我们再通过 defineModel 来实现上面的功能

  Home.vue
  
  <template>
    <Child v-model="city" v-model:address="address"></Child>
  </template>
  Child.vue
  
  <script lang="ts" setup>
    import { ref } from 'vue'
    import Child from '@/views/home/Child'
    const city = ref('bj')
    const address = ref('haidian')
  </script>

  <template>
    <input v-model="localCity" />
    <input v-model="localAddress" />
  </template>

  <script lang="ts" setup>
    const localCity = defineModel()
    // required 是否必传属性  default: 默认值
    const localAddress = defineModel('address', {
      required: true,
      default: 'myAddress'
    })
  </script>

如此简单

GitHub 加速计划 / vu / vue
207.54 K
33.66 K
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:2 个月前 )
73486cb5 * chore: fix link broken Signed-off-by: snoppy <michaleli@foxmail.com> * Update packages/template-compiler/README.md [skip ci] --------- Signed-off-by: snoppy <michaleli@foxmail.com> Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 4 个月前
e428d891 Updated Browser Compatibility reference. The previous currently returns HTTP 404. 5 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐