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

相关推荐
子兮曰3 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万3 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
A黄俊辉A3 天前
uniapp webview中实现 app和内嵌的H5双向通信
vue.js·json
三十而立洋3 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁3 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
honkun64 天前
vue 表格组件 vxe-table 配置 ajax 请求自动加载数据与表单查询
vue.js·vxe-table
kybs19914 天前
全球灾害数据分析可视化 毕业设计-附源码66794
vue.js·spring boot·mysql·安全·django·c#·asp.net
汉堡大王95274 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端