指令是 模板解析 的续章,本文会尝试从源码的角度来理解 指令 是如何被提取和应用的。

指令的提取

指令的提取过程是在parse阶段进行的,在 parseHTML 方法中,会解析字符串模板为如下的单个ast对象

  <div class="app">
hello {{ a }}
<span v-for='i in 5'>{{i}}</span>
</div> 被解析为如下文本 {
"type": 1,
"tag": "div",
"attrsList": [
{
"name": "class",
"value": "app"
}
],
"attrsMap": {
"class": "app"
},
"children": []
} 其中的 <span v-for='i in 5'>{{i}}</span> 被解析为如下文本 {
"type": 1,
"tag": "span",
"attrsList": [
{
"name": "v-for",
"value": "i in 5"
}
],
"attrsMap": {
"v-for": "i in 5"
},
"parent": {
"type": 1,
"tag": "div",
"attrsList": [],
"attrsMap": {
"class": "app"
},
"children": [
{
"type": 2,
"expression": "\"\\n hello \"+_s(a)+\"\\n \"",
"tokens": [
"\n hello ",
{
"@binding": "a"
},
"\n "
],
"text": "\n hello {{ a }}\n "
}
],
"plain": false,
"staticClass": "\"app\""
},
"children": []
}

通过提取为格式化的对象,就可以对单个的节点进行解析了

指令的解析

首先对 v-for , v-if , v-once 三个指令进行解析

// processFor 调用 parseFor,
// 通过 /([^]*?)\s+(?:in|of)\s+([^]*)/ 正则表达式match后,
// 将 v-for='i in 5' 解析为 {for: "5", alias: "i"} 对象
// 再把 {for: "5", alias: "i"} 与 element 对象合并
processFor(element) processIf(element) // 同上 processOnce(element) // 同上 // processElement 是一个比较大的方法,
// 里面对 key ref slot component attrs进行了提取和解析
// 其中的 processAttrs 方法,会提取attrs里面的 v-bind(:) v-on(@)
// 构造成props, attrsMap, events, directives等对象
// 然后与 element 对象合并
// 值得一提的是 v-model 会被当做props,然后再次进入directives中处理
processElement(element)

指令的处理

通过上面的步骤,Vue 提取出了 props, events, attrsMap , for 等指令对象,那么 Vue 又是如何去处理这些指令的呢? codegen/index.js 中有这样一些代码:

  ...
if (el.key) {
data += `key:${el.key},`
}
// ref
if (el.ref) {
data += `ref:${el.ref},`
}
...
if (el.attrs) {
data += `attrs:{${genProps(el.attrs)}},`
}
if (el.props) {
data += `domProps:{${genProps(el.props)}},`
}
if (el.events) {
data += `${genHandlers(el.events, false, state.warn)},`
}
...

上面这些代码会对每个属性进行处理,然后拼接为字符串

 比如这段代码
<div class="app">
hello {{ a }}
<span v-for='i in 5' @click='a'>{{i}}</span>
<input type="text" v-model='a'>
</div> 会被处理为
_c('div',{staticClass:"app"},[_v("\n hello "+_s(a)+"\n "),_l((5),function(i){return _c('span',{on:{"click":a}},[_v(_s(i))])}),_v(" "),_c('input',{directives:[{name:"model",rawName:"v-model",value:(a),expression:"a"}],attrs:{"type":"text"},domProps:{"value":(a)},on:{"input":function($event){if($event.target.composing)return;a=$event.target.value}}})],2) 这段代码在 to-function.js 中,会被 createFunction 处理为一个匿名函数

剩下的事情,就交给 vm.$createElement 去生成vNode了。

最新文章

  1. 设计模式(六)原型模式(Prototype Pattern)
  2. 【Java EE 学习 48】【Hibernate学习第五天】【抓取策略】【二级缓存】【HQL】
  3. EasyUI相关
  4. 定位form光标行
  5. Oracle 中的游标(用Javase中Iterator 类比之)
  6. SDP协议中的Continuation State
  7. HBase shell
  8. 【BZOJ】【1042】【HAOI2008】硬币购物
  9. STM32自带的bool型变量
  10. Java基础IO文件拷贝练习题
  11. cocos&#160;射线检测 3D物体 (Sprite3D点击)
  12. masonry 设置控件抗压缩及抗拉伸
  13. 手机端仿ios的银行下拉脚本五
  14. python程序—利用socket监控端口
  15. Idea书签管理器的使用
  16. 【BZOJ5020】【THUWC2017】在美妙的数学王国中畅游 LCT 泰勒展开
  17. idea 无效的源发行版: 8解决方法
  18. kafka-java客户端连接
  19. Ubuntu Server对OpenStack的支持
  20. win10关闭后台应用程序进程的方法

热门文章

  1. Mac Item2 &#35774;&#32622;&#21035;&#21517; &#27704;&#20037;&#29983;&#25928;
  2. ubuntu 12.04 64位 安装wps
  3. Oracle 关于WKT构造SDO_GEOMETRY的问题。
  4. loj6119 「2017 山东二轮集训 Day7」国王
  5. Android 4.4中AudioRecord用例 - 录制系统内置声音
  6. 有料面试题之--Object里面的方法
  7. Spring Boot Mock单元测试学习总结
  8. 7、Android---网络技术
  9. 造成MySQL全表扫描的原因
  10. VMware 虚拟机安装