前端 | 自定义组件 v-model:Vue 如何实现双向绑定
v-model 是 Vue 中一个常用的指令,常用于表单中的数据绑定。如下基本用法想必大家都很熟悉,data 中的 checked 属性的值就会随着多选框的状态实时变化。
<el-checkbox v-model="checked" />
但你或许听说过,Vue 组件之间是“单向数据流”,即通过 props 从父组件向子组件单向传递数据。那么,v-model 的“双向绑定”效果是如何实现的呢?
自定义组件实现 v-model
首先来看一个实际应用的例子,需求如下:在创建试卷页面 paperCreate 中,通过选择题目组件 questionSelect 查询并选择题目组成试卷,效果如下图所示。

为了方便使用,希望能在选择题目组件上使用 v-model 指令进行双向绑定:
<!-- 选择题目组件 -->
<question-select v-model="formData.questions" />
<!-- 显示已选择题目 -->
<div v-for="item in formData.questions" :key="item.id" >
<question :question="item" />
</div>
value 属性和 input 事件
自定义支持 v-model 的组件只需要满足两个条件:
- value 属性作为传入数据
- 数据改变时,将新数据作为 payload,向上 emit 一个 input 事件
就是这么简单,相关代码为:
export default {
props: {
value: Array, // 类型根据实际需要
},
methods: {
handelChange() {
this.$emit("input", newValue);
},
},
};
如果不想使用默认的 value 属性和 input 事件,也可以通过 model 对象自定义相应属性和事件:
model: {
prop: 'checked',
event: 'change',
},
单向数据流
需要注意的是,prop 传值是单向的,即父组件中的数据改变会反映到子组件中,但在子组件内部不能主动改变 prop 的值。具体来说就是,子组件中不能使用类似于 v-model="value" 之类试图改变 value 值的操作。
因此表格中的 checkbox,也只单向传入 value 来控制是否选中的状态,然后在选中状态改变时手动处理改变后的结果。
- 对于表格中的一行(即一道题目),如果传入的 value 数组(即已选中的题目列表)中包含它的 id,则显示为选中状态
- 不能直接改变原数组 value,直接构造新列表传出:
- 如果新增了一个选项,传原列表 + 所选对象
- 如果取消了一个选项,传原列表 - 所选对象
(PS:组件库中提供的 el-checkbox 实际上也是另一个自定义组件,可以同理分析)
<el-table :data="questionList">
<el-table-column>
<template slot-scope="scope">
<el-checkbox
:value="selectedIds.includes(scope.row.id)"
@change="(value) => handelChange(scope.row, value)"
/>
</template>
</el-table-column>
<!-- 其他属性 -->
</el-table>
props: {
value: Array,
},
computed: {
selectedIds() {
return this.value.map((item) => item.id);
},
},
methods: {
handelChange(item, checked) {
if (checked) {
this.$emit("input", [...this.value, item]);
} else {
this.$emit(
"input",
this.value.filter((element) => element.id != item.id)
);
}
},
},
具体写法与组件库的具体实现有关,简单说明一下此处的 element 语法:
- scope.row 为 el-table 表格当前行对应的对象
- el-checkbox 的 change 事件的负载为复选框点击后的新值
然后就结束了,父组件使用选择题目组件时就能正常使用 v-model 了。本例中绑定的数据是完整的题目列表,原因是需要在页面中显示已选择题目的具体信息;如果只需要 id 数据(例如 select 那样的组件),则 emit 时只传 id 列表即可,写法完全一致。
双向绑定
通过上面的例子想必你已经看出来了,v-model 指令的“双向绑定”实际上是一个语法糖:它将父组件的数据通过 prop 传入子组件,再监听子组件的输入事件来更新父组件中的数据,从而实现双向绑定的效果。

结语&参考资料
以上是个人对 Vue 中 v-model 指令的一些理解与思考,希望能给你提供帮助。如果有问题或疏漏之处,欢迎在评论中讨论与指正。
我将继续在个人博客中更新自己的学习笔记,以前端技术(Vue框架)为主,感兴趣的话欢迎关注!
参考资料:Vue 官方文档
前端 | 自定义组件 v-model:Vue 如何实现双向绑定的更多相关文章
- 前端开发组件化设计vue,react,angular原则漫谈
前端开发组件化设计vue,react,angular原则漫谈 https://www.toutiao.com/a6346443500179505410/?tt_from=weixin&utm_ ...
- 组件的通信 :provide / inject 对象进入后,就等于不用props,然后内部对象,直接复制可以接受数组,属性不能直接复制,可以用Object.assgin覆盖对象,或者Vue的set 双向绑定数据
组件的通信 :provide / inject 对象进入后,就等于不用props,然后内部对象,直接复制可以接受数组,属性不能直接复制,可以用Object.assgin覆盖对象,或者Vue的set 双 ...
- Vue的数据双向绑定和Object.defineProperty()
Vue是前端三大框架之一,也被很多人指责抄袭,说他的两个核心功能,一个数据双向绑定,一个组件化分别抄袭angular的数据双向绑定和react的组件化思想,咱们今天就不谈这种大是大非,当然我也没到达那 ...
- 剖析Vue原理&实现双向绑定MVVM-2
vue.js 最核心的功能有两个,一是响应式的数据绑定系统,二是组件系统.本文仅探究双向绑定是怎样实现的.先讲涉及的知识点,再用简化得不能再简化的代码实现一个简单的 hello world 示例. 一 ...
- Vue框架之双向绑定事件
Vue框架之双向绑定事件 首先介绍下Vue框架的语法 vue通过 {{temp}} 来渲染变量 {{count+100}} # 求和 v-text # 为标签插入text文本 v-html # 为标签 ...
- 用ES6的class模仿Vue写一个双向绑定
原文地址:用ES6的class模仿Vue写一个双向绑定 点击在线尝试一下 最终效果如下: 构造器(constructor) 构造一个TinyVue对象,包含基本的el,data,methods cla ...
- 原生js实现 vue的数据双向绑定
原生js实现一个简单的vue的数据双向绑定 vue是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时 ...
- angular4自定义组件非input元素实现ngModel双向数据绑定
在angular里我们一般都是给input元素添加[(ngModel)]="value"实现数据双向绑定,如果想实现自定义的组件上实现ngModel双向数据绑定应该怎么办呐... ...
- 【Vue】-- 数据双向绑定的原理 --Object.defineProperty()
Object.defineProperty()方法被许多现代前端框架(如Vue.js,React.js)用于数据双向绑定的实现,当我们在框架Model层设置data时,框架将会通过Object.def ...
随机推荐
- LuoguP7694 [COCI2009-2010#4] AUTORI 题解
Content 科学论文会大量引用一些早期的著作,因此在一个论文中出现两种不同的命名约定并不少见.这两种不同的命名约定分别是: 长变体,由每个作者姓氏的完整单词由连字符连接而成,例如 Knuth-Mo ...
- 『学了就忘』Linux系统定时任务 — 89、任务调度工具anacron
目录 1.任务调度工具anacron介绍 2.新旧版本Linux中anacron工具的区别 3./etc/cron.{daily,weekly,monthly}目录说明 4.anacron命令 5./ ...
- java 网络编程基础 InetAddress类;URLDecoder和URLEncoder;URL和URLConnection;多线程下载文件示例
什么是IPV4,什么是IPV6: IPv4使用32个二进制位在网络上创建单个唯一地址.IPv4地址由四个数字表示,用点分隔.每个数字都是十进制(以10为基底)表示的八位二进制(以2为基底)数字,例如: ...
- pycharm字体放大的设置
一.pycharm字体放大的设置 File -> setting -> Keymap ->在搜寻框中输入:increase -> Increase Font Size(双击) ...
- 资源分享 | PyTea:不用运行代码,静态分析pytorch模型的错误
前言 本文介绍一个Pytorch模型的静态分析器 PyTea,它不需要运行代码,即可在几秒钟之内扫描分析出模型中的张量形状错误.文末附使用方法. 本文转载自机器之心 编辑:CV技 ...
- PowerDotNet平台化软件架构设计与实现系列(09):消息平台
消息队列已经几乎成为大中型高吞吐应用的标配,继续根据我们一贯的节约代码的风格,为了复用的目标,抽象出消息队列平台,进行消息队列管理. 环境准备 1.(必须).Net Framework4.5+ 2.( ...
- C#验证对象中的属性是否为空的共通方法
在后台接口处理时,经常需要对请求的参数做验证.因此提取了共通方法,方便进行判断. /// <summary> /// 数据验证工具类 /// </summary> public ...
- SpringBoot整合Light Security框架
官方git地址:https://gitee.com/itmuch/light-security/tree/master 引入maven <dependency> <groupId&g ...
- IDEA设置调用方法时提示方法上的注释
IDEA设置代码注释提示,代码提示,鼠标放上面提示方法的注解信息 打开file-->setting-->Editor-->General,将Show quick documentat ...
- MFC中使用qt演练
链接 这里 note but , I dont guess that works in qt5