聊聊 vue2 与 vue3 的 v-model

从 vue2 聊起

v-model 这个指令主要用于处理双向绑定,对于原生元素可以直接这样写

js 复制代码
<input v-model="message" placeholder="请输入内容" />

当时写起来真是觉得厉害,加一个 v-model 就解决了双向绑定的问题。但随着项目的进展,很快就遇到了需要对组件进行 v-model 的操作,比如使用 ElementUI 的情况下

js 复制代码
<el-input v-model="username" placeholder="请输入用户名"></el-input>

居然也不需要额外的操作,于是那时候形成了一个意识,需要双向绑定时就直接 v-model 即可,但很快就栽了跟头。

有一个需求是需要对 input 做一个封装,于是很自然就写成了

js 复制代码
<my-input v-model="username" placeholder="请输入用户名"></el-input>

<template>
    <div>
        <input placeholder="请输入内容" />
    </div>
<template>

可想而知,v-model 完全没有生效,在这里卡了很久。上网查了相关资料才知道,原来 v-model 没有那么厉害。它的本质实际上只是做了个转化,也就是:

js 复制代码
<input v-model="message" placeholder="请输入内容" /> 
// 相当于
<input :value="message" @input="message = $event" placeholder="请输入内容"/>

由于 <input> 元素自带了 input 事件与 value 属性,所以自然就能监听到。此时进行输入时,会触发 @input,立刻进行赋值,所以 message 立刻进行了更新,也就是双向绑定的效果。

但转头一想,不对啊,为什么 <el-input> 这种组件也能支持呢,回去一看文档,原来这个组件也已经进行了类似的封装。

注:最新的 el-input 已经不再支持 v-model 了,笔者以前是用老版本的

大概就是

js 复制代码
// 父组件 v-model 编译后
<el-input :value="message" @input="message = $event" placeholder="请输入内容"/>

// 子组件
<template>
    <div>
        <input placeholder="请输入内容" :value="value" @input="$emit('input',$event.target.value)" />
    </div>
<template>

不得不提,语法糖虽好,让新手能很简单入手,但也隔开了后面的逻辑,出了 bug 理解成本和修改成本直线上升。 反观 react 的双向绑定就显得通俗易懂了

js 复制代码
// 父组件
<MyInput value={message} onChange={e => setMessage(e.target.value)} />

// 子组件
<input value={value} onChange={onChange} />

再探 vue3

vue2 的写法其实还能理解,拆成编译后的代码比较清晰。但 vue3 就显得拉胯了,看一段示例

js 复制代码
// 父组件
<MyInput v-model="message" />

// 子组件
<input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" />

有的同学可能已经有点迷糊了,这个 modelValue 是哪来的,这个 update:modelValue 又是什么?

老规矩,先看它编译成了什么吧

js 复制代码
<MyInput v-model="message" />

// 编译后
<MyInput :modelValue="message" @update:modelValue="message = $event" />

这下可能就能理解了,v-model 用 modelValue 作为了值,update:modelValue 作为了更新函数,并不关心你的传入参数叫什么,始终保持这个名字。

当然,可以手动进行命名

js 复制代码
<MyInput v-model:message="message" />

// 编译后
<MyInput :message="message" @update:message="message = $event" />

为什么 vue3 会将 v-model 设计成这样呢?其主要优点在于,可以同时兼容多个 v-model

js 复制代码
<MyInput v-model:title="title" v-model:content="content" />

// 编译后
<MyInput :title="title" @update:title="title = $event" :content="content" @update:content="content = $event" />

// 子组件
<template>
  <input :value="title" @input="$emit('update:title', $event.target.value)" placeholder="标题" />
  <input :value="content" @input="$emit('update:content', $event.target.value)" placeholder="内容" />
</template>
相关推荐
xixingzhe211 分钟前
本地桌面客户端入门开发
前端
不磕了还不行18 分钟前
用 Vue + Element UI 把元宝搜索的返回值做成“能点开检查的证据卡片”
前端·vue.js·ui
Csvn9 小时前
WASM
前端
修己xj11 小时前
我用 AI 给自己写了一个 Markdown 编辑器,然后把它开源了
前端
FRing0311 小时前
vue2干货总结2(v-bind、v-for、v-model、指令修饰符、v-bind操作class和style)
开发语言·前端·vue.js·vue2
幸运小猿11 小时前
模拟慢上传-处理超时重试image 丢失线上问题
前端·javascript·html
moshuying13 小时前
网购能买Token了!
前端
h_654321013 小时前
echarts实现柱状图加一条横线
前端·echarts
风骏时光牛马13 小时前
生成一个后端标题,只需要一个标题,不需要其他的任何文本。
前端
子非鱼@Itfuture13 小时前
关于前后端联调中登录状态/登录信息失效?
java·前端