聊聊 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>
相关推荐
前端小蜗3 小时前
🌐 利用Chrome内置 【AI翻译 API】实现国际化
前端·javascript·浏览器
寒月霜华3 小时前
JaveWeb后端-Web基础-SpringBoot Web、HTTP协议
前端·spring boot·http
袁煦丞3 小时前
管家婆远程开单自由飞!管家婆系统:cpolar内网穿透实验室第646个成功挑战
前端·程序员·远程工作
Dontla3 小时前
前端V0介绍(Vercel推出的AI前端生成工具)
前端·人工智能
fury_1233 小时前
vue3:trycatch里面可以在写一个trycatch吗
前端
苏纪云3 小时前
ES6~ES11新特性
前端·ecmascript·es6
阿金要当大魔王~~3 小时前
uniapp 请求携带数据 \\接口传值 \\ map遍历数据
前端·javascript·uni-app
十铭忘3 小时前
基于SAM2的眼动数据跟踪2
java·服务器·前端
hey_ner3 小时前
页面PDF文件格式预览(不使用pdf.js)
前端·javascript