本来准备开始之前打算好的新项目,打算基于taro进行多端开发。但是本地安装的版本太低,用taro update 更新版本,然后taro init 命令创建初始化项目后,项目根本跑步起来。缺少各种依赖...无语了...😶
昨天发的牢骚里感觉Vue的三个功能是解析并渲染html模板
,解析并执行js
,解析并渲染css样式
。然后有个核心概念vdom
,那么这个虚拟dom(vdom)
在代码里是怎么体现的呢。一起来看下。
如图:
从上至下,helpers
文件夹定义了一些类似工具方法的函数,比如:提取props
,合并hooks
,解析异步组件
,更新侦听器
。modules
文件夹定义了指令
和ref
相关的内容。三个create-**.js
定义了组件、元素、函数组件的创建方法。patch.js
则是虚拟dom的diff算法。vnode.js
则是对虚拟dom的定义。
从代码里看,vnode是一个类似如下的对象:
let myNode = {
tag:'div',
data:{
key:'1',
tag:'div',
class:"box-wrapper",
style:{width:'100%'},
props:{
name:'terrene',
},
attrs:{
alt:'pic'
},
on:{
click:()=>{console.log('click')}
},
},
children:[]
}
这个对象写出来以后,很容易联想到我们有时候在遇到vue表格自定义内容的时候,有时候会写一个render
函数,通常用h('div',{...})
来表示,这个h
函数里面其实就是这个vnode对象
。
创建vnode
实际上就是对vnode构造函数进行实例化。比如创建一个emptyNode(空节点)
。
export const createEmptyVNode = (text: string = '') => {
// 这里进行实例化操作
const node = new VNode()
node.text = text
node.isComment = true
return node
}
再比如创建一个文本节点textNode
export function createTextVNode (val: string | number) {
// 又是一个实例化操作
return new VNode(undefined, undefined, undefined, String(val))
}
同理,创建组件也是对vnode进行实例化的过程。但是由于组件包含了生命周期,实例化的过程中会将生命周期的钩子函数merge进去。
函数式组件先是定义了一个类vnode的构造函数,然后构造函数返回了一个由createElement
方法生成的一个vnode实例。
function FunctionalRenderContext (
data,
props,
children,
parent,
Ctor
) {
const options = Ctor.options
this.data = data
this.props = props
this.children = children
this.parent = parent
this.listeners = data.on || emptyObject
this.injections = resolveInject(options.inject, parent)
this.slots = () => resolveSlots(children, parent)
// ensure the createElement function in functional components
// gets a unique context - this is necessary for correct named slot check
const contextVm = Object.create(parent)
const isCompiled = isTrue(options._compiled)
const needNormalization = !isCompiled
// support for compiled functional template
if (isCompiled) {
// exposing $options for renderStatic()
this.$options = options
// pre-resolve slots for renderSlot()
this.$slots = this.slots()
this.$scopedSlots = data.scopedSlots || emptyObject
}
if (options._scopeId) {
this._c = (a, b, c, d) => {
const vnode: ?VNode = createElement(contextVm, a, b, c, d, needNormalization)
if (vnode) {
vnode.functionalScopeId = options._scopeId
vnode.functionalContext = parent
}
return vnode
}
} else {
this._c = (a, b, c, d) => createElement(contextVm, a, b, c, d, needNormalization)
}
}
createFunctionalComponent
函数返回了这个构造函数的实例。
export function createFunctionalComponent (
Ctor: Class<Component>,
propsData: ?Object,
data: VNodeData,
contextVm: Component,
children: ?Array<VNode>
): VNode | void {
const options = Ctor.options
const props = {}
const propOptions = options.props
if (isDef(propOptions)) {
for (const key in propOptions) {
props[key] = validateProp(key, propOptions, propsData || emptyObject)
}
} else {
if (isDef(data.attrs)) mergeProps(props, data.attrs)
if (isDef(data.props)) mergeProps(props, data.props)
}
// 实例化FunctionalRenderContext
const renderContext = new FunctionalRenderContext(
data,
props,
children,
contextVm,
Ctor
)
// 这里进行返回
const vnode = options.render.call(null, renderContext._c, renderContext)
if (vnode instanceof VNode) {
vnode.functionalContext = contextVm
vnode.functionalOptions = options
if (data.slot) {
(vnode.data || (vnode.data = {})).slot = data.slot
}
}
return vnode
}
源码是个工程化的东西,里面的逻辑非常复杂,而且方法的调用都是彼此相互引用。比如vdom中有很多地方也用到了lifecycle的方法。而lifecycle本身也是个非常复杂的东西。
这篇内容大致介绍了vdom
中涉及的内容以及vdom的创建。细节部分接下来会慢慢的拆解。
javascript基础知识总结
本文分享自 JavaScript高级程序设计 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!