Vue源码主要关注数据驱动、组件化、响应式部分。我个人不需要太纠结或者太着急去阅读源码。打好基础,熟悉之后,再深入了解会有很大的帮助。看了黄毅老师的文章,一边跟着源码写下内容,一边加上自己的理解。数据驱动(生成和获取vnode):第一篇文章考虑Vue如何生成节点并挂载它们。这里,我们只从以浏览器为平台的第一次渲染的角度,使用runtime+compilerversionnewVue(options)。很简单,直接调用_initthis._init(options)这个函数主要是调用配置合并函数,同时进行各种初始化工作,然后调用vm.$mount进行挂载,重点在于$mountvm.$mount(el,hydrating)(mount函数在platform文件夹下,因为内部实现和平台有关,hydrating参数和服务端渲染有关,所以这里不考虑)1先用mount缓存原始$mount(platform/web/runtime/index),然后重新定义$mount2新的$mount内部通过compileToFunctions获取render和staticRenderFns函数(或者通过sfc(vue-loader解析)获取render函数),即在runtime+compiler版本中,然后返回原始的mount调用结果。mount(el,hydrating)(原$mount)原来的mount函数很简单,主要是调用mountComponent(this,el,hydrating)函数mountComponent(this,el,hydrating)步骤:1触发beforemount钩子函数2定义updateComponent函数,函数内部调用实例vm._render()的vm._update(vm._render(),hydrating)函数中实际调用render函数生成vnode(见下文)3newWatcher(vm,updateComponent,noop,{before},true)生成watcher实例,watcher实例生成更新时会触发updateComponent,传入的before函数只是一个hook,函数内部是调用beforeUpdatehook组件的功能。4设置实例_isMounted为true,并调用挂载的钩子函数5返回实例vm_render()的核心部分是vnode=render.call(vm._renderProxy,vm.$createElement),然后返回生成的vnoderender()render函数的生成比较复杂,根据不同的环境生成,但是最终initRender函数中的vnode$createElement=createElement(vm,a,b,c,d,true)是调用我们常见的生成的createElement(也叫h函数)createElement函数,是对_createElement函数的封装,处理传入的参数后调用_createElement(context,tag,data,children,normalizationType)_createElement(context,tag,data,children,normalizationType)。关注两个关键点:进程子进程的规范化和VNode的创建。1Childrennormalization(生成vnode数组):当normalizationType为ALWAYS_NORMALIZE时:normalizeChildren(children)当normalizationType为SIMPLE_NORMALIZE时:simpleNormalizeChildren(children)simpleNormalizeChildren:默认内部生成的children都是Vnode类型(调用场景为compileandgeneraterender),只有功能组件生成数组。所以处理很简单,就是遍历children判断是否是数组,压平返回normalizeChildren:调用方法有两种场景。一种情况是渲染函数是用户手写的。当children中只有一个节点时,Vue.js从接口层开始,允许用户将children写成一个基本类型来创建一个单一的简单文本节点。此时会调用createTextVNode创建一个文本节点的VNode;另一种场景是编译slot和v-for时会生成一个嵌套数组,此时会调用normalizeArrayChildren方法normalizeArrayChildren:该方法是遍历children并将其转化为vnode。如果遇到数组,将递归调用此函数。注意:如果有两个连续的文本节点,则合并为一个文本节点2创建Vnode如果标签是字符串类型:1是普通标签,则直接newVnode2否则检查标签是否为已注册componenttag,如果有则调用createComponent3否则创建一个vnode,tag未知如果tagComponenttype:componenttype后续会解释:直接创建一个componenttypevnode3返回生成的vnode使用好处很多vnode。一方面不需要直接使用原生的重dom,虚拟节点更轻量,丢弃了很多dom的属性方法,定制化程度更高。其次,它也可以用于vue框架的多平台使用。源代码如下:
