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

指令的提取

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

  1. <div class="app">
  2. hello {{ a }}
  3. <span v-for='i in 5'>{{i}}</span>
  4. </div>
  5. 被解析为如下文本
  6. {
  7. "type": 1,
  8. "tag": "div",
  9. "attrsList": [
  10. {
  11. "name": "class",
  12. "value": "app"
  13. }
  14. ],
  15. "attrsMap": {
  16. "class": "app"
  17. },
  18. "children": []
  19. }
  20. 其中的 <span v-for='i in 5'>{{i}}</span> 被解析为如下文本
  21. {
  22. "type": 1,
  23. "tag": "span",
  24. "attrsList": [
  25. {
  26. "name": "v-for",
  27. "value": "i in 5"
  28. }
  29. ],
  30. "attrsMap": {
  31. "v-for": "i in 5"
  32. },
  33. "parent": {
  34. "type": 1,
  35. "tag": "div",
  36. "attrsList": [],
  37. "attrsMap": {
  38. "class": "app"
  39. },
  40. "children": [
  41. {
  42. "type": 2,
  43. "expression": "\"\\n hello \"+_s(a)+\"\\n \"",
  44. "tokens": [
  45. "\n hello ",
  46. {
  47. "@binding": "a"
  48. },
  49. "\n "
  50. ],
  51. "text": "\n hello {{ a }}\n "
  52. }
  53. ],
  54. "plain": false,
  55. "staticClass": "\"app\""
  56. },
  57. "children": []
  58. }

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

指令的解析

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

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

指令的处理

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

  1. ...
  2. if (el.key) {
  3. data += `key:${el.key},`
  4. }
  5. // ref
  6. if (el.ref) {
  7. data += `ref:${el.ref},`
  8. }
  9. ...
  10. if (el.attrs) {
  11. data += `attrs:{${genProps(el.attrs)}},`
  12. }
  13. if (el.props) {
  14. data += `domProps:{${genProps(el.props)}},`
  15. }
  16. if (el.events) {
  17. data += `${genHandlers(el.events, false, state.warn)},`
  18. }
  19. ...

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

  1. 比如这段代码
  2. <div class="app">
  3. hello {{ a }}
  4. <span v-for='i in 5' @click='a'>{{i}}</span>
  5. <input type="text" v-model='a'>
  6. </div>
  7. 会被处理为
  8. _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)
  9. 这段代码在 to-function.js 中,会被 createFunction 处理为一个匿名函数

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

Vue2.0原理-指令的更多相关文章

  1. vue2.0自定义指令

    前面一片文章说了vue2.0过滤器,其实自定义指令跟过滤器非常相似,单就定义方式而言,其与过滤器完全一致,分为局部指令,和全局指令.不过就是filter改为directive的区别. 过滤器一般用于对 ...

  2. vue2.0 v-model指令

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  3. vue2.0自定义指令的使用方法

    感觉2.0好坑啊,自定义指令和1.0完全不一样,并且文档写得也不太清晰,下面是我写得一个demo,希望帮助大家更好地理解自定义指令 <!DOCTYPE html> <html lan ...

  4. Vue2.0原理-模板解析

    下面这段代码,vue内部做了什么操作?我去源码里面找找看 new Vue({ el: '#app' }) 入口 vue 的入口文件在 src/core/instance/index.js, 里面一进来 ...

  5. vue2.0 自定义指令详解

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  6. vue2.0版本指令v-if与v-show的区别

    v-if: 判断是否加载,可以减轻服务器的压力,在需要时加载. v-show:调整css dispaly属性,可以使客户端操作更加流畅. v-if示例: <!DOCTYPE html> & ...

  7. 基于vue2.0原理-自己实现MVVM框架之computed计算属性

    基于上一篇data的双向绑定,这一篇来聊聊computed的实现原理及自己实现计算属性. 一.先聊下Computed的用法 写一个最简单的小demo,展示用户的名字和年龄,代码如下: <body ...

  8. Vue2.0 - 自定义指令 vue-directive

    Vue.directive('指令',function(el,binding,vnode){ el.style='color:'+binding.value;}); el : 指令所绑定的元素,可以用 ...

  9. vue2.0 自定义指令

    Vue指令 Vue的指令以v-开头,作用在HTML元素上,将指令绑定在元素上,给绑定的元素添加一些特殊行为. 例如: <h1 v-if="yes">Yes</h1 ...

随机推荐

  1. 我做SAP CRM One Order redesign的一些心得体会

    框架开发和应用程序的开发完全不一样. 举个具体的最近折腾我的例子: 创建新的service order,维护header的shipping data,此时order和shipping data的mod ...

  2. php 访问控制和重载

    一     php 类中定义的private/protected属性,类外部是无法访问的,但是 我们可以通过public方法来访问设置这些属性 如下 <?php class test{ priv ...

  3. 嵌套的ng-repeat双层循环,内层如何获取外层的$index?

    html代码: <div> <ul ng-repeat="row in table track by $index"> <li ng-repeat=& ...

  4. 3192: [JLOI2013]删除物品

    3192: [JLOI2013]删除物品 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 1366 Solved: 794 [Submit][Statu ...

  5. 最易懂的layui分页

    该篇文章是在layui前端框架之分页基础上简洁化和详细化. 首先该示例采用的是Spring+MyBatis Plus+SpringMVC(常规的SSM框架),持久层换成MyBatis也行. 至于lay ...

  6. JavaScript实现计时器

    var myVar=setInterval(function(){myTimer()},1000); function myTimer() { var d = new Date(); document ...

  7. MySQL(四)执行计划

    转载自:Oo若离oO,原文链接 在MySQL中使用explain查询SQL的执行计划 目录 一.什么是执行计划 二.如何分析执行计划 一.什么是执行计划 要对执行计划有个比较好的理解,需要先对MySQ ...

  8. 【原型图】Mockplus

    Mockplus   原型设计工具

  9. CCF认证201712-1最小差值

    问题描述 给定n个数,请找出其中相差(差的绝对值)最小的两个数,输出它们的差值的绝对值. 输入格式 输入第一行包含一个整数n. 第二行包含n个正整数,相邻整数之间使用一个空格分隔. 输出格式 输出一个 ...

  10. Linux中定时删除超过指定大小的文件夹

    背景: 开发环境总是动不动就没有空间了, 大部分都是debug日志.所以有必要在日志很疯狂的时候,删除不必要的日志. 思路:一. 书写删除日志文件脚本: 定时任务执行.  但是有时候的日志是需要保存用 ...