编译

之前我们分析过模板到真实    DOM    渲染的过程,中间有⼀个环节是把模板编译成        render        函数,这个 过程我们把它称作编译。 虽然我们可以直接为组件编写        render        函数,但是编写        template        模板更加直观,也更符合我们的 开发习惯。 Vue.js    提供了    2    个版本,⼀个是    Runtime    +    Compiler    的,⼀个是    Runtime    only    的,前者是包含编译代码 的,可以把编译过程放在运⾏时做,后者是不包含编译代码的,需要借助    webpack    的        vue-loader        事 先把模板编译成        render    函数。 这⼀章我们就来分析编译的过程,对编译过程的了解会让我们对    Vue    的指令、内置组件等有更好的理 解。不过由于编译的过程是⼀个相对复杂的过程,我们只要求理解整体的流程、输⼊和输出即可,对 于细节我们不必抠太细。有些细节⽐如对于        slot        的处理我们可以在之后去分析插槽实现的时候再详 细分析。
 

编译⼊⼝ 

那么接下来的章节我会带⼤家去逐步分析这⼏个过程。

总结

编译⼊⼝逻辑之所以这么绕,是因为    Vue.js    在不同的平台下都会有编译的过程,因此编译过程中的依 赖的配置        baseOptions        会有所不同。⽽编译过程会多次执⾏,但这同⼀个平台下每⼀次的编译过程 配置⼜是相同的,为了不让这些配置在每次编译过程都通过参数传⼊,Vue.js    利⽤了函数柯⾥化的技巧 很好的实现了        baseOptions        的参数保留。同样,Vue.js    也是利⽤函数柯⾥化技巧把基础的编译过程 函数抽出来,通过        createCompilerCreator(baseCompile)        的⽅式把真正编译的过程和其它逻辑如 对编译配置处理、缓存处理等剥离开,这样的设计还是⾮常巧妙的。
 

parse

 

流程图

总结

那么⾄此,    parse        的过程就分析完了,看似复杂,但我们可以抛开细节理清它的整体流程。    parse    的⽬标是把        template        模板字符串转换成    AST    树,它是⼀种⽤    JavaScript    对象的形式来描述整个模 板。那么整个        parse        的过程是利⽤正则表达式顺序解析模板,当解析到开始标签、闭合标签、⽂本 的时候都会分别执⾏对应的回调函数,来达到构造    AST    树的⽬的。 AST    元素节点总共有    3    种类型,    type        为    1    表⽰是普通元素,为    2    表⽰是表达式,为    3    表⽰是纯⽂ 本。其实这⾥我觉得源码写的不够友好,这种是典型的魔术数字,如果转换成⽤常量表达会更利于源 码阅读。 当    AST    树构造完毕,下⼀步就是        optimize        优化这颗树。
 

optimize

 

 

codegen

 

 

 

 

⾮常经典的事件中⼼的实现,把所有的事件⽤        vm._events        存储起来,当执⾏        vm.$on(event,fn)    的时候,按事件的名称        event        把回调函数        fn        存储起来        vm._events[event].push(fn)    。当执⾏    vm.$emit(event)        的时候,根据事件名        event        找到所有的回调函数        let    cbs    = vm._events[event]    ,然后遍历执⾏所有的回调函数。当执⾏        vm.$off(event,fn)        的时候会移除指 定事件名        event        和指定的        fn        当执⾏        vm.$once(event,fn)        的时候,内部就是执⾏        vm.$on    ,并 且当回调函数执⾏⼀次后再通过        vm.$off        移除事件的回调,这样就确保了回调函数只执⾏⼀次。 所以对于⽤户⾃定义的事件添加和删除就是利⽤了这⼏个事件中⼼的    API。需要注意的事⼀ 点,    vm.$emit        是给当前的        vm        上派发的实例,之所以我们常⽤它做⽗⼦组件通讯,是因为它的回 调函数的定义是在⽗组件中,对于我们这个例⼦⽽⾔,当⼦组件的        button        被点击了,它通过    this.$emit('select')        派发事件,那么⼦组件的实例就监听到了这个        select        事件,并执⾏它的 回调函数——定义在⽗组件中的        selectHandler        ⽅法,这样就相当于完成了⼀次⽗⼦组件的通讯。 总结 那么⾄此我们对    Vue    的事件实现有了进⼀步的了解,Vue    ⽀持    2    种事件类型,原⽣    DOM    事件和⾃定义 事件,它们主要的区别在于添加和删除事件的⽅式不⼀样,并且⾃定义事件的派发是往当前实例上派 发,但是可以利⽤在⽗组件环境定义回调函数来实现⽗⼦组件的通讯。另外要注意⼀点,只有组件节 点才可以添加⾃定义事件,并且添加原⽣    DOM    事件需要使⽤        native        修饰符;⽽普通元素使⽤    .native        修饰符是没有作⽤的,也只能添加原⽣    DOM    事件。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值