详解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 相关文章推荐
限制复选框的最大可选数
Jul 01 Javascript
两个listbox实现选项的添加删除和搜索
Mar 01 Javascript
JavaScript中的style.display属性操作
Mar 27 Javascript
js中cookie的添加、取值、删除示例代码
Oct 21 Javascript
jquery中ready()函数执行的时机和window的load事件比较
Jun 22 Javascript
手机软键盘弹出时影响布局的解决方法
Dec 15 Javascript
JS重载实现方法分析
Dec 16 Javascript
select下拉框插件jquery.editable-select详解
Jan 22 Javascript
jQuery实现点击DIV同时点击CheckBox,并为DIV上背景色的实例
Dec 18 jQuery
vue项目中使用Hbuilder打包app 设置沉浸式状态栏的方法
Oct 22 Javascript
JS实现在线ps功能详解
Jul 31 Javascript
vue瀑布流组件实现上拉加载更多
Mar 10 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 验证图片生成函数
2009/05/21 PHP
php生成扇形比例图实例
2013/11/06 PHP
CI框架开发新浪微博登录接口源码完整版
2014/05/28 PHP
php利用事务处理转账问题
2015/04/22 PHP
php实现替换手机号中间数字为*号及隐藏IP最后几位的方法
2016/11/16 PHP
PHP单例模式详解及实例代码
2016/12/21 PHP
Redis构建分布式锁
2017/03/28 PHP
老生常谈PHP面向对象之命令模式(必看篇)
2017/05/24 PHP
PHP大文件切割上传功能实例分析
2019/07/01 PHP
使用composer安装使用thinkphp6.0框架问题【视频教程】
2019/10/01 PHP
用js判断浏览器是否是IE的比较好的办法
2007/05/08 Javascript
jquery 插件 任意位置浮动固定层
2008/12/25 Javascript
jQuery AJAX回调函数this指向问题
2010/02/08 Javascript
iframe 异步加载技术及性能分析
2011/07/19 Javascript
浅谈js中用$(#ID)来作为选择器的问题(id重复的时候)
2017/02/14 Javascript
javascript 组合按键事件监听实现代码
2017/02/21 Javascript
jquery实现弹窗功能(窗口居中显示)
2017/02/27 Javascript
微信小程序获取手机网络状态的方法【附源码下载】
2017/12/08 Javascript
Angular6 发送手机验证码按钮倒计时效果实现方法
2019/01/08 Javascript
浅谈webpack性能榨汁机(打包速度优化)
2019/01/09 Javascript
Angular中使用ng-zorro图标库部分图标不能正常显示问题
2019/04/22 Javascript
Node.js 在本地生成日志文件的方法
2020/02/07 Javascript
[01:09:23]KG vs TNC 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/16 DOTA
Python进程通信之匿名管道实例讲解
2015/04/11 Python
详解Django中的权限和组以及消息
2015/07/23 Python
python使用代理ip访问网站的实例
2018/05/07 Python
详解Python3.6的py文件打包生成exe
2018/07/13 Python
Python Collatz序列实现过程解析
2019/10/12 Python
pytorch 实现模型不同层设置不同的学习率方式
2020/01/06 Python
使用Keras训练好的.h5模型来测试一个实例
2020/07/06 Python
英国二手iPhone、音乐、电影和游戏商店:musicMagpie
2018/10/26 全球购物
个人求职简历的自我评价范文
2013/10/09 职场文书
机械制造专业个人的自我评价
2013/12/28 职场文书
办公室岗位职责
2014/02/12 职场文书
《九色鹿》教学反思
2014/02/27 职场文书
CSS3中Animation实现简单的手指点击动画的示例
2021/07/15 HTML / CSS