v-model原理

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

  • 通过props设置子组件的状态
  • 通过监听子组件发出的事件改变父组件的状态,从而影响子组件的props值

通过以上两个部分,实现了父组件的状态和子组件状态进行了绑定的效果。

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="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框中输入内容可以在父组件区域实时显示,达到了子组件中状态和父组件状态实时绑定的效果。

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

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

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

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>

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

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

解析部分

在将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,然后添加到实例的指令中

将指令相关内容添加到实例指令中
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实例上指令格式的转换

指令设置部分

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

调用指令的构造函数
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的种类进行不同的创建函数进行创建,如果我们自定义指令需要在子组件上添加属性,也需要在这个函数里面进行操作

普通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上设置事件处理函数

指令响应变化部分

createPatchFunction统一处理指令的钩子函数

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

  • bind
  • inserted
  • update
  • componentUpdated
  • unbind

总结

编译过程

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

初始化过程

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

深入了解v-model流程的更多相关文章

  1. model流程

    @RequestMapping("toDetail.do") public ModelAndView toDetail(HttpServletRequest request,Htt ...

  2. PHP 流程管理

    添加新流程页面: <div> 请选择流程节点:<br /><br /> <?php session_start(); include("../DBD ...

  3. PHP 流程

    登录页面 <body> <form action="loginchuli.php" method="post"> <div> ...

  4. PHP流程管理,堪比小小程序

    这个流程管理是从用户登录界面开始,然后提交申请,页面逐级审核通过.这个做起来其实挺简单,只是在某些逻辑方面需要 好好考虑一下. 登录页面就不再多说了,如果要存session的话,我们可以建一个假的登录 ...

  5. PHP实现流程管理功能

    核心逻辑:流程管理,在各种系统中扮演很重要的地位,可以把设定好的流程放入系统中,规定好几个节点,只要所有节点都通过,就可以通过. 建立四张数据库表: 1.我们首先做一个新建流程页面 flow.php, ...

  6. 什么是V模型?使用SDLC和STLC学习案例研究

    本教程详细介绍了软件/系统开发生命周期(SDLC),如瀑布循环和迭代循环,如RAID和Agile.此外,它继续解释测试的V模型和STLC(软件测试生命周期). 假设为您分配了一项任务,即为客户开发自定 ...

  7. php实现简单的流程管理

    流程管理,在各种系统中扮演很重要的地位,可以把设定好的流程放入系统中,规定好几个节点,只要所有节点都通过,就可以通过. 惯例,先看数据库: 我们首先做一个新建流程页面,先把节点做好 xinjian.p ...

  8. php……流程

    流程:由两个及以上的业务步骤,完成一个完整的业务行为的过程,可称之为流程:注意是两个及以上的业务步骤.事物进行过程中的次序或顺序的布置和安排. 创建页面: 登录页面(login.php): <h ...

  9. 用ajax和PHP实现简单的流程管理

    首先要先有一个新建流程的页面xinjian.php <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ...

  10. 不可错过的效能利器「GitHub 热点速览 v.22.39」

    如果你是一名前端工程师且维护着多个网站,不妨试试本周榜上有名的 HTML-first 的 Qwik,提升网站访问速度只用一招.除了提升网站加载速度的 Qwik,本周周榜上榜的 Whisper 也是一个 ...

随机推荐

  1. C/C++编程笔记:C++入门知识丨函数和函数模板

    本篇要学习的内容和知识结构概览 函数的参数及其传递方式 1. 函数参数传递方式 传值: 传变量值: 将实参内存中的内容拷贝一份给形参, 两者是不同的两块内存 传地址值: 将实参所对应的内存空间的地址值 ...

  2. Ynoi专练

    为了练习分块 莫队 bitset黑科技 我会写几道Ynoi 放到这里. bitset 每一位占1bit int 每一位占 4 bitye bool占1 bitye long long 8bitye L ...

  3. 解析laravel之redis简单模块操作

    入门级操作 普通 set / get 操作: set操作,如果键名存在,则会覆盖原有的值: $redis = app('redis.connection'); $redis->set('libr ...

  4. 区块链钱包开发 - USDT - 二、创建交易错误以及解决方法

    这里总结了开发中一些常见报错和解决方案 1. 提示:createRawtx_change "Amount is not a number" 解决:参数中 tx 的 amout 需要 ...

  5. Flink的流处理API(二)

    一.Environment 1,getExecutionEnvironment getExecutionEnvironment会根据查询运行的方式决定返回什么样的运行环境,是最常用的一种创建执行环境的 ...

  6. JVM进行篇

                                              结合字节码指令理解Java虚拟机栈和栈帧          栈帧:每个栈帧对应一个被调用的方法,可以理解为一个方法的 ...

  7. 【av68676164(p54)】段式和段页式虚拟存储

    段式存储管理 进程分段 把进程按逻辑意义划分为多个段,每段有段名,长度不定,进程由多段组成 例:一个具有代码段.数据段和堆栈段的进程 段式内存管理系统的内存分配 以段为的单位装入,每段分配连续的内存 ...

  8. tableauRFM分析

    1.数据源 2.创建相关字段 2.1 购买点会员生命期 2.2 会员最后购买时间 2.3 最后购买点生命期 3.近一个月老客户的生命期情况 排除了当天创建当天购买的情况,可以看到超市的大部分用户是两年 ...

  9. C#LeetCode刷题之#367-有效的完全平方数(Valid Perfect Square)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3869 访问. 给定一个正整数 num,编写一个函数,如果 num ...

  10. C#LeetCode刷题之#387-字符串中的第一个唯一字符(First Unique Character in a String)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3939 访问. 给定一个字符串,找到它的第一个不重复的字符,并返回 ...