[组件封装]关于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...

相关推荐
摆烂工程师1 分钟前
炸裂了~兄弟们,GPT4o出图效果太好了
前端·后端·程序员
开心小老虎2 分钟前
用HTML和CSS生成炫光动画卡片
前端·css·html
米粒宝的爸爸9 分钟前
vue3 vue-router 传递路由参数
前端·javascript·vue.js
前端同学14 分钟前
react版本主要区别
前端·react.js·前端框架
2401_8784545344 分钟前
Es6进阶
前端·javascript·es6
KarajanKing1 小时前
elementUI的el-table 树状表格本地模糊搜索并返回原有格式进行展示等
前端
鲁子狄1 小时前
[笔记] 多层 Nginx反向代理与Docker容器化前端应用部署 : 客户端 -> 本地 Nginx -> Docker 内的 Nginx -> 前端应用
前端·后端·docker
能说一句爱我吗1 小时前
前端操作窗口返回结果的多种方式
前端·vue.js
前端极客探险家1 小时前
React Query 4 核心技术解析:从自动缓存到无限滚动优化
前端·react.js·缓存
Cutey9161 小时前
解决 Input Number 输入框出现科学计数法(如 -1e-18)的问题
前端·javascript·面试