creatApp的源码原理
// 1.创建app对象
// ensureRenderer() ,和渲染相关的代码都在这里,待会儿我们会读到
const app = ensureRenderer().createApp(...args)
if (__DEV__) {
injectNativeTagCheck(app)
injectCustomElementCheck(app)
}
// 2.这里取出了app中的mount方法,因为待会儿要进行重写
const { mount } = app
// 3.重写mount方法
// 这里重写的目的是考虑到跨平台(app.mount里面只包含和平台无关的代码)
// 这些重写的代码都是一些和web关系比较大的代码(比如其他平台也可以进行类似的重写)
app.mount = (containerOrSelector: Element | ShadowRoot | string): any => {
// normalizeContainer方法就是在web端获取我们的元素,比如div#app
const container = normalizeContainer(containerOrSelector)
if (!container) return
const component = app._component
if (!isFunction(component) && !component.render && !component.template) {
component.template = container.innerHTML
}
// clear content before mounting
// 先清空container中的原本内容
container.innerHTML = ''
// 调用真正的mount函数, 进行挂载
const proxy = mount(container, false, container instanceof SVGElement)
if (container instanceof Element) {
container.removeAttribute('v-cloak')
container.setAttribute('data-v-app', '')
}
return proxy
}
// 3.返回app
return app
}) as CreateAppFunction<Element>
组件的vNode和组件的instance有什么区别
Vnode是虚拟DOM,形成树构造的一个个节点
instance是保存组件的各种状态
template有多个根节点处理情况
runtime-core→renderer.ts→baseCreateRenderer→patch
会被当成Fragment组件节点包裹处理
1、createApp
2、app.mount
3、rerender的render
4、再调用patch函数 判断类型
5、是组件类型就调用processComponent,看组件有没有挂载
6、没有挂载就调用mountComponent
7、创建组件实例Instance
8、初始化setupComponent(instance)
9、setuprerenderEffet()判断有没有挂载
10、没有挂载就取出subtree
11、再次来到patch判断el
12、通过processElement来处理
13、通过创建document.createElement()
14、有子节点的情况下就调用mountChildren,for循环拿到一个个小children再次调用patch(null,children),判断是组件还是元素
通过render函数生成vNode的时候会有以下情况:
1、对于不会改变的静态节点,进行作用域的提升,不会生成vnode
2、diff算法,patch操作不会对静态节点进行操作,diff那些有可能修改的vnode,
let normalizedProps
if (key[0] !== '$') {
const n = accessCache![key]
if (n !== undefined) {
switch (n) {
case AccessTypes.SETUP:
return setupState[key]
case AccessTypes.DATA:
return data[key]
case AccessTypes.CONTEXT:
return ctx[key]
case AccessTypes.PROPS:
return props![key]
// default: just fallthrough
}
} else if (setupState !== EMPTY_OBJ && hasOwn(setupState, key)) {
accessCache![key] = AccessTypes.SETUP
return setupState[key]
} else if (data !== EMPTY_OBJ && hasOwn(data, key)) {
accessCache![key] = AccessTypes.DATA
return data[key]
} else if (
// only cache other properties when instance has declared (thus stable)
// props
(normalizedProps = instance.propsOptions[0]) &&
hasOwn(normalizedProps, key)
) {
accessCache![key] = AccessTypes.PROPS
return props![key]
} else if (ctx !== EMPTY_OBJ && hasOwn(ctx, key)) {
accessCache![key] = AccessTypes.CONTEXT
return ctx[key]
} else if (!__FEATURE_OPTIONS_API__ || shouldCacheAccess) {
accessCache![key] = AccessTypes.OTHER
}
}
根据源码展示:查找值的优先顺序是:$全局>setUp>data>prop>context(methods、computed)