跳至主要內容

快去试用下 Vue3 新特性 defineModel,贼好用

Bing🐣VueVue3defineModel大约 2 分钟

快去试用下 Vue3 新特性 defineModel,贼好用

具体讨论可以参见该RFC,看名字可能有的人就知道可能是和v-model有关了,你猜的没错,新出的defineModel可以更加快捷的自定义组件上的v-model

举个例子 🌰

以前的写法我们自定义一个v-model需要写很多东西,包括propsemit触发更新。

<template>
  <div class="child">
    <input :value="modelValue" @input="onInput" />
  </div>
</template>

<script lang="ts" setup>
const props = defineProps({
  modelValue: String
})
const emit = defineEmits<{
  (e: 'update:modelValue', value: string): void
}>()

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

defineModel的新写法,只需要写 2 行代码就行了,是不是瞬间觉得代码看这清爽多了。

<template>
  <div class="child">
    <input :value="modelValue" @input="onInput" />
  </div>
</template>

<script lang="ts" setup>
const modelValue = defineModel<string>()

function onInput(e: Event) {
  const target = e.target as HTMLInputElement
  modelValue.value = target.value
}
</script>

详细语法

// 如果你不喜欢TS,可以不用定义类型
const modelValue = defineModel()
// ^? Ref<any>
modelValue.value = 10

// 支持泛型的形式定义参数类型,如string
const modelValue = defineModel<string>()
// ^? Ref<string | undefined>
modelValue.value = 'hello'

// 支持prop的required写法
const modelValue = defineModel<string>({ required: true })
// ^? Ref<string>

// 支持指定v-model的名称,如v-model:count
const count = defineModel<number>('count')
count.value++

// 支持默认值写法
const count = defineModel<number>('count', { default: 0 })
// ^? Ref<number>

本地 Local 模式

defineModel选项对象还额外提供了一个local参数,当设置为 true 的时候,即时没有写v-model也能够本地 发生变化。

<template>
  <!-- local模式 -->
  <Comp />
</template>

官网还贴心的准备了一个小Demo,有兴趣的也可以直接打开看看。

启用 defineModel

// vite.config.js
export default {
  plugins: [
    vue({
      script: {
        defineModel: true
      }
    })
  ]
}

vue-cli

注意

需要 vue-loader@^17.1.1

// vue.config.js
module.exports = {
  chainWebpack: (config) => {
    config.module
      .rule('vue')
      .use('vue-loader')
      .tap((options) => {
        return {
          ...options,
          defineModel: true
        }
      })
  }
}