详解vue v-model


Posted in Javascript onAugust 31, 2020

1. v-model原理

vue中v-model是一个语法糖,所谓的语法糖就是对其他基础功能的二次封装而产生的功能。简单点说,v-model本身就是父组件对子组件状态以及状态改变事件的封装。其实现原理上分为两个部分:

通过props设置子组件的状态
通过监听子组件发出的事件改变父组件的状态,从而影响子组件的props值
通过以上两个部分,实现了父组件的状态和子组件状态进行了绑定的效果。

1.1 demo

v-model使用示例

<!DOCTYPE html>
<html>
 <head>
 <meta charset="utf-8" />
 <title>v-model示例</title>
 <script type="text/javascript" src="vue.js"></script>
 </head>

 <body>
 <div id="app">
 <div>这里是父组件的状态:</div>
 <div style="margin-bottom: 15px;">{{content}}</div>
 <Child v-model="content"></Child>
 </div>

 <template id="input">
 <div>
 <div>这里是子组件的输入区域:</div>
 <input :value="value" @input="contentChange" />
 </div>
 </template>

 <script type="text/javascript">
 var Child = {
 template: "#input",
 props: {
 value: {
 type: String,
 required: true
 }
 },
 methods: {
 contentChange(value){
 this.$emit("input", value.target.value);
 }
 }
 };

 var vueInstance = new Vue({
 el: "#app",
 components: {Child},
 data: {
 content: ""
 }
 })
 </script>
 </body>
</html>

在浏览器中打开上述html页面,可以看到实时效果:在子组件中的input框中输入内容可以在父组件区域实时显示,达到了子组件中状态和父组件状态实时绑定的效果。

2. 修改v-model默认监听的事件和设置prop的名称

v-model指令默认是在子组件上设置的prop名称是value,默认监听子组件上的input事件,在上面的demo上,如果我们修改子组件contentChange函数中发出的事件名称,在父组件中就无法实时获取到子组件的输入。

Vue中提供了通过在子组件上定义model属性来修改这两个参数名称的功能,不过该功能需要在版本2.2以上才能使用,如下demo所示:

2.1 demo

<!DOCTYPE html>
<html>
 <head>
 <meta charset="utf-8" />
 <title>v-model示例</title>
 <script type="text/javascript" src="vue.js"></script>
 </head>

 <body>
 <div id="app">
 <div>这里是父组件的状态:</div>
 <div style="margin-bottom: 15px;">{{content}}</div>
 <Child v-model="content"></Child>
 </div>

 <template id="input">
 <div>
 <div>这里是子组件的输入区域:</div>
 <input :value="content" @input="contentChange" />
 </div>
 </template>

 <script type="text/javascript">
 var Child = {
 template: "#input",
 model: {
 prop: "content",
 event: "contentChanged"
 },
 props: {
 content: {
 type: String,
 required: true
 }
 },
 methods: {
 contentChange(value){
 this.$emit("contentChanged", value.target.value);
 }
 }
 };

 var vueInstance = new Vue({
 el: "#app",
 components: {Child},
 data: {
 content: ""
 }
 })
 </script>
 </body>
</html>

3. Vue中对v-model指令处理分析

基于Vue2.0版本,分析我们在标签上写上v-model属性到vue组件实现响应的流程。

3.1 解析部分

3.1.1 在将HTML解析称AST时,会解析HTML中标签的属性

function processAttrs(el){
 ...
 name = name.replace(dirRE, '')
 // parse arg
 const argMatch = name.match(argRE)
 if (argMatch && (arg = argMatch[1])) {
 name = name.slice(0, -(arg.length + 1))
 }
 addDirective(el, name, value, arg, modifiers)
 ...
}

提取指令的名称,v-model的指令名称name为model,然后添加到实例的指令中

3.1.2 将指令相关内容添加到实例指令中

export function addDirective (
 el: ASTElement,
 name: string,
 value: string,
 arg: ?string,
 modifiers: ?{ [key: string]: true }
) {
 (el.directives || (el.directives = [])).push({ name, value, arg, modifiers })
}

在实例的指令属性中添加相应的指令,这样就实现了从html上的属性到Vue实例上指令格式的转换

3.2 指令设置部分

在将html解析称AST之后,实例对应的directives属性上就有了我们设置的v-model相关的值,包括参数值value,name是model

3.2.1 调用指令的构造函数

function genDirectives (el: ASTElement): string | void {
 const dirs = el.directives
 if (!dirs) return
 let res = 'directives:['
 let hasRuntime = false
 let i, l, dir, needRuntime
 for (i = 0, l = dirs.length; i < l; i++) {
 dir = dirs[i]
 needRuntime = true
 const gen = platformDirectives[dir.name] || baseDirectives[dir.name]
 if (gen) {
 // compile-time directive that manipulates AST.
 // returns true if it also needs a runtime counterpart.
 needRuntime = !!gen(el, dir, warn)
 }
 ...
}

在v-model指令的构造函数中会根据tag的种类进行不同的创建函数进行创建,如果我们自定义指令需要在子组件上添加属性,也需要在这个函数里面进行操作

3.2.2 普通tag下的v-model指令构造过程

function genDefaultModel 
 el: ASTElement,
 value: string,
 modifiers: ?Object
): ?boolean {
 ...
 addProp(el, 'value', isNative ? `_s(${value})` : `(${value})`)
 addHandler(el, event, code, null, true)
 ...
}
  • addProp在el上设置一个名称为value的prop,同时设置其值
  • addHandler在el上设置事件处理函数

3.3 指令响应变化部分

3.3.1 createPatchFunction统一处理指令的钩子函数
createPatchFunction函数返回一个patch函数,在patch处理过程中,会调用指令的钩子函数,包括:

  • bind
  • inserted
  • update
  • componentUpdated
  • unbind

4. 总结

4.1 编译过程

  1. 从html上解析所设置的指令
  2. 通过gen*函数将指令设置到AST上
  3. 调用指令的构造函数,设置指令需要在编译时期处理的事情

4.2 初始化过程

通过在patch函数中,调用统一的钩子函数,触发指令的钩子函数,实现相应的功能

以上就是详解vue v-model的详细内容,更多关于vue v-model的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
javascript新建标签,判断键盘输入,以及判断焦点(示例代码)
Nov 25 Javascript
JS实用的动画弹出层效果实例
May 05 Javascript
BootStrap响应式导航条实例介绍
May 06 Javascript
AngularJS上拉加载问题解决方法
May 23 Javascript
JavaScript学习笔记整理_简单实现枚举类型,扑克牌应用
Sep 19 Javascript
JavaScript 栈的详解及实例代码
Jan 22 Javascript
干货!教大家如何选择Vue和React
Mar 13 Javascript
关于Ajax的原理以及代码封装详解
Sep 08 Javascript
Node.js学习之TCP/IP数据通讯(实例讲解)
Oct 11 Javascript
微信小程序实现传参数的几种方法示例
Jan 10 Javascript
vue router 跳转后回到顶部的实例
Aug 31 Javascript
Vue.js项目实战之多语种网站的功能实现(租车)
Aug 07 Javascript
vue.js 输入框输入值自动过滤特殊字符替换中问标点操作
Aug 31 #Javascript
vue路由结构可设一层方便动态添加路由操作
Aug 31 #Javascript
element-ui tree结构实现增删改自定义功能代码
Aug 31 #Javascript
vue elementui tree 任意级别拖拽功能代码
Aug 31 #Javascript
Element-ui树形控件el-tree自定义增删改和局部刷新及懒加载操作
Aug 31 #Javascript
JS遍历树层级关系实现原理解析
Aug 31 #Javascript
Element-ui el-tree新增和删除节点后如何刷新tree的实例
Aug 31 #Javascript
You might like
PHP安全技术之 实现php基本安全
2010/09/04 PHP
PHP统计nginx访问日志中的搜索引擎抓取404链接页面路径
2014/06/30 PHP
PHP实现限制域名访问的实现代码(本地验证)
2020/09/13 PHP
如何让您的中波更粗更长 - 中波框形天线制作
2021/03/10 无线电
Javascript 网页黑白效果实现代码(兼容IE/FF等)
2010/04/23 Javascript
基于jquery的文章中所有图片width大小批量设置方法
2013/08/01 Javascript
Javascript中的回调函数和匿名函数的回调示例介绍
2014/05/12 Javascript
express的中间件cookieParser详解
2014/12/04 Javascript
Jquery的基本对象转换和文档加载用法实例
2015/02/25 Javascript
WEB前端实现裁剪上传图片功能
2016/10/17 Javascript
jquery实现文本框的禁用和启用
2016/12/07 Javascript
Angular.Js的自动化测试详解
2016/12/09 Javascript
Bootstrap栅格系统简单实现代码
2017/03/06 Javascript
js获取 gif 的帧数的代码实例
2019/09/10 Javascript
JavaScript将数组转换为链表的方法
2020/02/16 Javascript
element-plus一个vue3.xUI框架(element-ui的3.x 版初体验)
2020/12/02 Vue.js
python实现ip查询示例
2014/03/26 Python
python生成密码字典的方法
2018/07/06 Python
python全局变量引用与修改过程解析
2020/01/07 Python
python 回溯法模板详解
2020/02/26 Python
Xadmin+rules实现多选行权限方式(级联效果)
2020/04/07 Python
Python基于进程池实现多进程过程解析
2020/04/30 Python
Python通过队列来实现进程间通信的示例
2020/10/14 Python
python调用百度API实现人脸识别
2020/11/17 Python
意大利在线药房:Saninforma
2021/02/11 全球购物
公司营业员的工作总结自我评价
2013/10/05 职场文书
小学语文课后反思精选
2014/04/25 职场文书
干部作风建设个人剖析材料
2014/10/11 职场文书
2014年银行信贷员工作总结
2014/12/08 职场文书
学生保证书
2015/01/16 职场文书
幼儿园亲子活动通知
2015/04/24 职场文书
学习焦裕禄观后感
2015/06/09 职场文书
邹越演讲观后感
2015/06/15 职场文书
浙江省杭州市平均工资标准是多少?
2019/07/09 职场文书
教你用Python爬取英雄联盟皮肤原画
2021/06/13 Python
MySQL REVOKE实现删除用户权限
2021/06/18 MySQL