详解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插件slides实现无缝轮播图特效
Apr 17 Javascript
使用AOP改善javascript代码
May 01 Javascript
JS+CSS实现鼠标滑过时动态翻滚的导航条效果
Sep 24 Javascript
JS本地刷新返回上一页代码
Jul 25 Javascript
工作中比较实用的JavaScript验证和数据处理的干货(经典)
Aug 03 Javascript
js获取浏览器高度 窗口高度 元素尺寸 偏移属性的方法
Nov 21 Javascript
微信小程序 获取当前地理位置和经纬度实例代码
Dec 05 Javascript
JS实现的样式切换功能tableCSS实例
Dec 30 Javascript
浅谈JavaScript中的apply/call/bind和this的使用
Feb 26 Javascript
80%应聘者都不及格的JS面试题
Mar 21 Javascript
layerui代码控制tab选项卡,添加,关闭的实例
Sep 04 Javascript
使用vue3重构拼图游戏的实现示例
Jan 25 Vue.js
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短信接口代码
2016/05/13 PHP
php封装的pdo数据库操作工具类与用法示例
2019/05/08 PHP
php实现映射操作实例详解
2019/10/02 PHP
js的onload事件及初始化按钮事件示例代码
2013/09/25 Javascript
标题过长使用javascript按字节截取字符串
2014/04/24 Javascript
基于JS实现移动端访问PC端页面时跳转到对应的移动端网页
2020/12/24 Javascript
js判断价格,必须为数字且不能为负数的实现方法
2016/10/07 Javascript
js 文字超出长度用省略号代替,鼠标悬停并以悬浮框显示实例
2016/12/06 Javascript
js实现图片切换(动画版)
2016/12/25 Javascript
微信小程序 生命周期和页面的生命周期详细介绍
2017/01/19 Javascript
javascript数组去重常用方法实例分析
2017/04/11 Javascript
win系统下nodejs环境安装配置
2017/05/04 NodeJs
angular 用拦截器统一处理http请求和响应的方法
2017/06/08 Javascript
ES6 javascript的异步操作实例详解
2017/10/30 Javascript
微信小程序签到功能
2018/10/31 Javascript
vue 组件开发原理与实现方法详解
2019/11/29 Javascript
Vue中使用wangeditor富文本编辑的问题
2021/02/07 Vue.js
使用python进行文本预处理和提取特征的实例
2018/06/05 Python
Python Pandas数据结构简单介绍
2019/07/03 Python
Python实现微信机器人的方法
2019/09/06 Python
Python 2种方法求某个范围内的所有素数(质数)
2020/01/31 Python
基于梯度爆炸的解决方法:clip gradient
2020/02/04 Python
Python运行异常管理解决方案
2020/03/09 Python
CSS3属性background-size使用指南
2014/12/09 HTML / CSS
在HTML5 Canvas中放入图片和保存为图片的方法
2014/05/03 HTML / CSS
详解通过focusout事件解决IOS键盘收起时界面不归位的问题
2019/07/18 HTML / CSS
德国baby-markt婴儿用品瑞士网站:baby-markt.ch
2017/06/09 全球购物
加拿大时装零售商:Influence U
2018/12/22 全球购物
英国家居装饰品、户外家具和玻璃器皿购物网站:Rinkit.com
2019/11/04 全球购物
建筑自我鉴定
2013/10/19 职场文书
计算机专业推荐信范文
2013/11/27 职场文书
建筑设计学生的自我评价
2014/01/16 职场文书
离婚协议书范本(2014版)
2014/09/28 职场文书
教师批评与自我批评
2014/10/15 职场文书
启迪人心的励志语录:脾气永远不要大于本事
2020/01/02 职场文书
详解nodejs内置模块
2021/05/06 NodeJs