[组件封装]关于Vue3中如何封装多个v-model

前言

大家好,我是辉夜真是太可爱啦。

(本文仅适合刚入门v3的小白用户如何自行封装 v-model)

文本主要讲述在 Vue3 中如何一步步封装 v-model ,为何要使用 currentValue 进行变量中转,以及为何要使用 watch 监听 ,以及和 Vue2 中不同的是,如何封装多个 v-model。以及文末提及了最新的 defineModel

ok,那我们先从简单的一个 input封装开始。

首先,先了解, v-model 其实就是一个语法糖,其实就是父组件中

<ChildComponent v-model:modelValue="inputValue" />

的语法糖缩写。

我们可以将上面的代码进行进一步的拆分。

<ChildComponent :modelValue="inputValue" @update:modelValue="(val)=>inputValue = val" />

现在大家应该理解了,说白了就是 子组件中 emit('update:modelValue') 以及 props:modelValue 的组合,就是那么简单。(如果对于emit以及props也不太清楚,可以往下看,笔者有着相应的说明)

只是 modelValue 是官方指定的默认值,v-model:modelValue 可以省略为 v-model

那么,我们来代码实现一下。

定义 props:modelValue

props在子组件中定义,当父组件使用v-bind绑定子组件中定义的props时,可以从父组件中将变量的值传入子组件中,且实时更新

在子组件中,首先定义一个输入框,以及定义一个 props

javascript 复制代码
<template>
  <el-input v-model="modelValue" />
</template>

<script setup>
import { defineProps } from 'vue'

const props = defineProps({
  modelValue: {
    type: String,
    default: '',
  },
})
</script>

v-model 无法直接绑定 props

我们发现,程序直接报错了,给了我们提示 Use a v-bind binding combined with a v-on listener that emits update:x event instead.

大意就是 v-model 不能直接绑定 props ,所以我们通过一个变量来中转一下。

我们加一行 let currentValue = ref(props.modelValue)

然后将 el-input 绑定这个 currentValue

现在代码如下:

javascript 复制代码
<template>
  <el-input v-model="currentValue" />
</template>

<script setup>
import { defineProps, ref } from 'vue'

const props = defineProps({
  modelValue: {
    type: String,
    default: '',
  },
})

let currentValue = ref(props.modelValue)
</script>

实现 emit('update:modelValue')

emit主要是在子组件中定义,可以通过 emit('自定义的emit事件','想要传递的值')来向父组件传值,在父组件中,通过@自定义的emit事件,来接收子组件中传入的值

我们可以通过 @update:modelValue 监听输入框的变化,将它的值传递给父组件。

先定义 emit 事件

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

接下来,我们就可以使用 emit('update:modelValue', currentValue.value) 去更新值了。

javascript 复制代码
<template>
  <el-input v-model="currentValue" @input="updateValue" />
</template>

<script setup>
import { defineProps, ref, defineEmits } from 'vue'

const props = defineProps({
  modelValue: {
    type: String,
    default: '',
  },
})

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

let currentValue = ref(props.modelValue)

const updateValue = (value) => {
  currentValue.value = value
  emit('update:modelValue', currentValue.value)
}
</script>

父组件使用

javascript 复制代码
<template>
  <MyInput v-model="inputValue" />
</template>

<script setup>
import MyInput from '@/components/MyInput.vue'

let inputValue = ref('test')
</script>

为了更加方便效果的展示了,我们可以在 MyInput 后面加入 {{inputValue}} ,可以看到,当子组件中输入框更改时,父组件中的 inputValue 也会实时更新。

关于 watch 监听 modelValue

但是,比方说我们在父组件中加入一个按钮,点击他即可以改变 inputValue 的值

javascript 复制代码
<MyInput v-model="inputValue" /> {{ inputValue }}
<el-button type="primary" size="default" @click="inputValue = '重置'">重置</el-button>

点击按钮之后,我们会发现,父组件中更新了值,但是子组件中不会触发更新。

还记得我们由于之前弄了个 currentValue 值的中转吗,modelValue 更新了,但是没有触发 currentValue 的更新,所以我们可以用一个 watch 监听 modelValue 的变化。

javascript 复制代码
watch(
  () => props.modelValue,
  (newValue) => {
    currentValue.value = newValue
  }
)

当然,这仅限于如果你需要父组件中的更新,实时响应到子组件中,那你可以添加一个watch监听

如何v-model:show

比方说我现在有一个弹窗,我需要实现 v-model:show,那怎么办呢,很简单,你只需要将子组件中的 modelValue 全局替换为 show

也就是说 定义 props:show 使用 emit('update:show'), 父组件中使用 v-model:show 即可。

javascript 复制代码
<template>
  <el-dialog v-model="currentShow" title="标题" :before-close="handleClose">
    <div>我的弹窗</div>
  </el-dialog>
</template>

<script setup>
const props = defineProps({
  show: {
    type: Boolean,
    default: false,
  },
})

const emit = defineEmits(['update:show'])

let currentShow = ref(props.show)
watch(
  () => props.show,
  (newValue) => {
    currentShow.value = newValue
  }
)
const handleClose = () => {
  currentShow.value = false
  emit('update:show', currentShow.value)
}
</script>

实现多个 v-model

相比于v2,我们还可以使用多个v-model。

例如我们实现一个弹窗组件 v-model:show 控制弹窗的显示隐藏, v-model控制输入框中的值。

Vue3 中,我们可以将相同的功能块进行分块处理。

子组件:

javascript 复制代码
<template>
  <el-dialog v-model="currentShow" title="标题" :before-close="handleClose">
    <el-input v-model="currentValue" @input="updateValue" />
  </el-dialog>
</template>

<script setup>
const props = defineProps({
  show: {
    type: Boolean,
    default: false,
  },
  modelValue: {
    type: String,
    default: '',
  },
})

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

let currentValue = ref(props.modelValue)
watch(
  () => props.modelValue,
  (newValue) => {
    currentValue.value = newValue
  }
)
const updateValue = (value) => {
  currentValue.value = value
  emit('update:modelValue', currentValue.value)
}

let currentShow = ref(props.show)
watch(
  () => props.show,
  (newValue) => {
    currentShow.value = newValue
  }
)
const handleClose = () => {
  currentShow.value = false
  emit('update:show', currentShow.value)
}
</script>

父组件:

javascript 复制代码
<template>
  <MyDialog v-model:show="dialogShow" v-model="inputValue" />
</template>

<script setup>
import MyDialog from '@/components/MyDialog.vue'

let dialogShow = ref(true)
let inputValue = ref('test')
</script>

defineModel

在了解完基础使用之后,官方还推出了新的 defineModel()需要注意的是,这是Vue3.4+ 推出的功能,使用前先确认自己的版本是否高于 3.4

感兴趣的可以点击这里查看cn.vuejs.org/api/sfc-scr...

相关推荐
崔庆才丨静觅8 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60619 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了9 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅9 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅9 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅10 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment10 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅10 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊10 小时前
jwt介绍
前端
爱敲代码的小鱼10 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax