Vue.js 组件实例创建和管理代码详解
Vue.js 组件实例创建和管理代码详解
该代码片段展示了 Vue.js 中创建和管理组件实例的核心逻辑。下面将对代码中的关键部分进行详细解释和注释。
const InternalObjectKey = `__vInternal`;
function guardReactiveProps(props) {
if (!props)
return null;
return isProxy(props) || InternalObjectKey in props ? extend({}, props) : props;
}
const emptyAppContext = createAppContext();
let uid = 0;
function createComponentInstance(vnode, parent, suspense) {
const type = vnode.type;
const appContext = (parent ? parent.appContext : vnode.appContext) || emptyAppContext;
const instance = {
uid: uid++, // 组件实例唯一标识
vnode, // 虚拟节点
type, // 组件类型
parent, // 父组件实例
appContext, // 应用上下文
root: null, // 根组件实例
next: null, // 下一个组件实例
subTree: null, // 渲染结果
effect: null, // 副作用函数
update: null, // 更新函数
scope: new EffectScope( // 副作用作用域
true
/* detached */
),
render: null, // 渲染函数
proxy: null, // 代理对象
exposed: null, // 暴露给外部的属性
exposeProxy: null, // 暴露给外部的代理对象
withProxy: null, // 用于 `with` 语法的代理对象
provides: parent ? parent.provides : Object.create(appContext.provides), // 父级组件提供的依赖
accessCache: null, // 缓存访问的属性
renderCache: [], // 渲染缓存
// local resolved assets
components: null, // 组件
directives: null, // 指令
// resolved props and emits options
propsOptions: normalizePropsOptions(type, appContext), // props 选项
emitsOptions: normalizeEmitsOptions(type, appContext), // emits 选项
// emit
emit: null, // 事件发射函数
emitted: null, // 已发射的事件
// props default value
propsDefaults: EMPTY_OBJ, // props 默认值
// inheritAttrs
inheritAttrs: type.inheritAttrs, // 是否继承 attrs 属性
// state
ctx: EMPTY_OBJ, // 组件上下文
data: EMPTY_OBJ, // 数据
props: EMPTY_OBJ, // props
attrs: EMPTY_OBJ, // attrs
slots: EMPTY_OBJ, // slots
refs: EMPTY_OBJ, // refs
setupState: EMPTY_OBJ, // setup 状态
setupContext: null, // setup 上下文
// suspense related
suspense, // suspense 对象
suspenseId: suspense ? suspense.pendingId : 0, // suspense 标识
asyncDep: null, // 异步依赖
asyncResolved: false, // 异步解析状态
// lifecycle hooks
// not using enums here because it results in computed properties
isMounted: false, // 是否已挂载
isUnmounted: false, // 是否已卸载
isDeactivated: false, // 是否已停用
bc: null, // beforeCreate 钩子
c: null, // created 钩子
bm: null, // beforeMount 钩子
m: null, // mounted 钩子
bu: null, // beforeUpdate 钩子
u: null, // updated 钩子
um: null, // beforeUnmount 钩子
bum: null, // beforeUpdate 钩子
da: null, // deactivated 钩子
a: null, // activated 钩子
rtg: null, // renderTracked 钩子
rtc: null, // renderTriggered 钩子
ec: null, // errorCaptured 钩子
sp: null // serverPrefetch 钩子
};
{
instance.ctx = createDevRenderContext(instance); // 开发环境下的渲染上下文
}
instance.root = parent ? parent.root : instance; // 根组件实例
instance.emit = emit.bind(null, instance); // 事件发射函数
if (vnode.ce) {
vnode.ce(instance); // 创建组件实例时执行的钩子
}
return instance;
}
let currentInstance = null;
const getCurrentInstance = () => currentInstance || currentRenderingInstance;
const setCurrentInstance = (instance) => {
currentInstance = instance;
instance.scope.on(); // 开启副作用作用域
};
const unsetCurrentInstance = () => {
currentInstance && currentInstance.scope.off(); // 关闭副作用作用域
currentInstance = null;
};
const isBuiltInTag = /* @__PURE__ */ makeMap("slot,component");
function validateComponentName(name, config) {
const appIsNativeTag = config.isNativeTag || NO;
if (isBuiltInTag(name) || appIsNativeTag(name)) {
warn("Do not use built-in or reserved HTML elements as component id: " + name);
}
}
解释:
-
InternalObjectKey:一个用于标识对象是否被处理过的字符串常量,用于避免重复处理。 -
guardReactiveProps(props):一个函数,用于确保传入的 props 对象是响应式的。如果 props 对象本身就是一个响应式代理,或者已经被处理过(即包含了InternalObjectKey),则返回一个浅拷贝的 props 对象;否则返回原始 props 对象。 -
createComponentInstance(vnode, parent, suspense):一个函数,用于创建一个组件实例。该函数接收三个参数:vnode:一个虚拟节点对象,用于描述组件的元信息。parent:一个可选的组件实例,表示当前组件实例的父级组件。suspense:一个可选的 suspense 对象,表示当前组件实例所处的 suspense 状态。
该函数返回一个组件实例对象,包含了该组件实例的各种状态和方法,例如:
uid:组件实例唯一标识vnode:虚拟节点type:组件类型parent:父组件实例appContext:应用上下文root:根组件实例next:下一个组件实例subTree:渲染结果effect:副作用函数update:更新函数scope:副作用作用域render:渲染函数proxy:代理对象exposed:暴露给外部的属性exposeProxy:暴露给外部的代理对象withProxy:用于with语法的代理对象provides:父级组件提供的依赖accessCache:缓存访问的属性renderCache:渲染缓存components:组件directives:指令propsOptions:props 选项emitsOptions:emits 选项emit:事件发射函数emitted:已发射的事件propsDefaults:props 默认值inheritAttrs:是否继承 attrs 属性ctx:组件上下文data:数据props:propsattrs:attrsslots:slotsrefs:refssetupState:setup 状态setupContext:setup 上下文suspense:suspense 对象suspenseId:suspense 标识asyncDep:异步依赖asyncResolved:异步解析状态isMounted:是否已挂载isUnmounted:是否已卸载isDeactivated:是否已停用- 生命周期钩子函数
-
getCurrentInstance()和setCurrentInstance(instance):两个函数,用于获取和设置当前的组件实例。在组件渲染过程中,会通过setCurrentInstance(instance)将当前组件实例保存到一个全局变量中,以便在需要时能够访问它。 -
isBuiltInTag(name)和validateComponentName(name, config):两个函数,用于检查组件名称是否合法。其中isBuiltInTag(name)用于检查组件名称是否为内置标签或组件,而validateComponentName(name, config)则用于检查组件名称是否合法(例如是否与内置标签或组件重名),如果不合法,则会发出警告。
该代码片段展现了 Vue.js 中创建和管理组件实例的核心流程,为开发者理解 Vue.js 的组件机制提供了基础。
注意: 这段代码仅展示了部分核心逻辑,实际的 Vue.js 代码会更加复杂,包含了更多细节和优化。
原文地址: https://www.cveoy.top/t/topic/lR9y 著作权归作者所有。请勿转载和采集!