目录
vue3中实例化一个vue,是从createApp开始的,那我们createApp到底做了啥呢?
createApp源码
const createApp = ((...args) => {
const app = ensureRenderer().createApp(...args);
{
injectNativeTagCheck(app);
injectCompilerOptionsCheck(app);
}
const { mount } = app;
app.mount = (containerOrSelector) => {...};
return app;
});
ensureRenderer
初始化 一些方法(主要是渲染相关的方法),初始化一个app对象
function baseCreateRenderer(options, createHydrationFns)
... 初始化了一些方法
const internals = {
p: patch,
um: unmount,
m: move,
r: remove,
mt: mountComponent,
mc: mountChildren,
pc: patchChildren,
pbc: patchBlockChildren,
n: getNextHostNode,
o: options
};
let hydrate;
let hydrateNode;
if (createHydrationFns) {
[hydrate, hydrateNode] = createHydrationFns(internals);
}
return {
render,
hydrate,
createApp: createAppAPI(render, hydrate)
};
}
function createAppAPI(render, hydrate) {
return function createApp(rootComponent, rootProps = null) {
//此处简化
const context = {
app: {
_uid: uid++,
_component: rootComponent,
_props: rootProps,
_container: null,
_context: context,
_instance: null,
version,
get config() { return context.config;},
set config(v) {...},
use(plugin, ...options) {...},
mixin(mixin) {...},
directive(name, directive) {...},
mount(rootContainer, isHydrate, isSVG) {...},
unmount() {...},
provide(key, value) {...}
},
config: {
isNativeTag: NO,
performance: false,
globalProperties: {},
optionMergeStrategies: {},
errorHandler: undefined,
warnHandler: undefined,
compilerOptions: {}
},
mixins: [],
components: {},
directives: {},
provides: Object.create(null),
optionsCache: new WeakMap(),
propsCache: new WeakMap(),
emitsCache: new WeakMap()
};
return context.app;
}
}
injectNativeTagCheck
对app.config.isNativeTag 做响应式处理
Object.defineProperty(app.config, 'isNativeTag', {
value: (tag) => isHTMLTag(tag) || isSVGTag(tag),
writable: false
});
injectCompilerOptionsCheck
和 injectNativeTagCheck 差不多,对 app.config.isCustomElement 和 app.config.compilerOptions 做响应式只读处理。
mount源码
const { mount } = app;
app.mount = (containerOrSelector) => {
const container = normalizeContainer(containerOrSelector);
if (!container)
return;
const component = app._component;
if (!isFunction(component) && !component.render && !component.template) {
// __UNSAFE__
// Reason: potential execution of JS expressions in in-DOM template.
// The user must make sure the in-DOM template is trusted. If it's
// rendered by the server, the template should not contain any user data.
component.template = container.innerHTML;
}
// clear content before mounting
container.innerHTML = '';
const proxy = mount(container, false, container instanceof SVGElement);
if (container instanceof Element) {
container.removeAttribute('v-cloak');
container.setAttribute('data-v-app', '');
}
return proxy;
};
normalizeContainer
获取挂载位置,源码简化:
return isString(container) ? document.querySelector(container) : container;
mount
挂载
mount(rootContainer, isHydrate, isSVG) {
if (!isMounted) {
const vnode = createVNode(rootComponent, rootProps);
// store app context on the root VNode.
// this will be set on the root instance on initial mount.
vnode.appContext = context;
// HMR root reload
{
context.reload = () => {
render(cloneVNode(vnode), rootContainer, isSVG);
};
}
if (isHydrate && hydrate) {
hydrate(vnode, rootContainer);
}
else {
render(vnode, rootContainer, isSVG);
}
isMounted = true;
app._container = rootContainer;
rootContainer.__vue_app__ = app;
{
app._instance = vnode.component;
devtoolsInitApp(app, version);
}
return getExposeProxy(vnode.component) || vnode.component.proxy;
}else {报错}
}
createVNode
生成一个虚拟dom【vnode】
hydrate 与 render
挂载虚拟dom
(1)先 ensureRenderer【初始化 一些方法(主要是渲染相关的方法)】;
(2)再patch。patch 方法,主要是 mountElement 和 patchElement;
- mountElement 挂载,挂载时走这一步,onBeforeMount和 onMounted;
- patchElement 更新时,走这一步。