详解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 相关文章推荐
jQuery点击后一组图片左右滑动的实现代码
Aug 16 Javascript
javascript游戏开发之《三国志曹操传》零部件开发(一)让静态人物动起来
Jan 23 Javascript
jquery text(),val(),html()方法区别总结
Nov 04 Javascript
jquery批量设置属性readonly和disabled的方法
Jan 24 Javascript
《JavaScript DOM 编程艺术》读书笔记之DOM基础
Jan 09 Javascript
jQuery validate验证插件使用详解
May 11 Javascript
jquery.guide.js新版上线操作向导镂空提示jQuery插件(推荐)
May 20 jQuery
vue组件的写法汇总
Apr 12 Javascript
vue动态路由配置及路由传参的方式
May 23 Javascript
vue-router源码之history类的浅析
May 21 Javascript
微信公众号生成新浪短网址的实现(快速生成)
Aug 18 Javascript
JS实现打字游戏
Dec 17 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
PHP5.2中date()函数显示时间与北京时间相差8小时的解决办法
2009/05/28 PHP
PHP sprintf()函数用例解析
2011/05/18 PHP
选择PHP作为网站开发语言的原因分享
2012/01/03 PHP
PHPMailer邮件发送的实现代码
2013/05/04 PHP
yii2 modal弹窗之ActiveForm ajax表单异步验证
2016/06/13 PHP
微信自定义菜单的创建/查询/取消php示例代码
2016/08/05 PHP
限制文本字节数js代码
2007/03/06 Javascript
javascript Excel操作知识点
2009/04/24 Javascript
JavaScript接口实现代码 (Interfaces In JavaScript)
2010/06/11 Javascript
利用JQuery的load函数动态加载其它页面的内容的实现代码
2010/12/14 Javascript
更换select下拉菜单背景样式的实现代码
2011/12/20 Javascript
AspNet中使用JQuery boxy插件的确认框
2015/05/20 Javascript
jQuery切换所有复选框选中状态的方法
2015/07/02 Javascript
jquery解析XML及获取XML节点名称的实现代码
2016/05/18 Javascript
AngularJS 路由和模板实例及路由地址简化方法(必看)
2016/06/24 Javascript
jQuery操作复选框(CheckBox)的取值赋值实现代码
2017/01/10 Javascript
Vue2.0 给Tab标签页和页面切换过渡添加样式的方法
2018/03/13 Javascript
使用JS判断页面是首次被加载还是刷新
2019/05/26 Javascript
基于Vue SEO的四种方案(小结)
2019/07/01 Javascript
详解vue beforeRouteEnter 异步获取数据给实例问题
2019/08/09 Javascript
Vue开发中遇到的跨域问题及解决方法
2020/02/11 Javascript
JavaScript 双向链表操作实例分析【创建、增加、查找、删除等】
2020/04/28 Javascript
Python中使用MELIAE分析程序内存占用实例
2015/02/18 Python
Python中shutil模块的学习笔记教程
2017/04/04 Python
Python使用tkinter库实现文本显示用户输入功能示例
2018/05/30 Python
python中单下划线(_)和双下划线(__)的特殊用法
2019/08/29 Python
Python3将jpg转为pdf文件的方法示例
2019/12/13 Python
年终晚会主持词
2014/03/25 职场文书
遵纪守法演讲稿
2014/05/23 职场文书
开学典礼策划方案
2014/05/28 职场文书
品质标语大全
2014/06/21 职场文书
电气工程及其自动化专业毕业生自荐信
2014/06/21 职场文书
2015年社区反邪教工作总结
2015/10/14 职场文书
宣传委员竞选稿
2015/11/19 职场文书
《狼王梦》读后感:可怜天下父母心
2019/11/01 职场文书
java解析XML详解
2021/07/09 Java/Android