getCurrentInstance
// runtime-core/component.ts
let currentInstance = null;
export function getCurrentInstance() {
return currentInstance;
}
function setCurrentInstance(instance) {
currentInstance = instance;
}
在 setup 调用之前设置
// runtime-core/component.ts
function setupStatefulComponent(instance) {
const Component = instance.type;
const { setup } = Component;
// 实现组件对象的代理
...
if(setup) {
// 需要在 setup 调用之前设置
setCurrentInstance(instance);
const setupResult = setup(shallowReadonly(instance.props), {
emit: instance.emit,
});
setCurrentInstance(null);
// 处理 setup函数的返回结果
...
}
}
实现 provide inject
provide inject 可以实现父子通信/跨层级通信,所以给组件实例添加一个 parent,表示父虚拟节点的实例。
// runtime-core/component.ts
export function createComponentInstance(vnode, parent) {
const component = {
provides: parent ? parent.provides : {},
parent,
};
return component;
}
provide
// runtime-core/apiInject.ts
export function provide(key, value) {
// 存
const currentIsntance: any = getCurrentInstance();
if(currentIsntance) {
let { provides } = currentIsntance;
const parentProvides = currentIsntance.parent.provides;
// init
if(provides === parentProvides) {
// A = Object.create(B),把 B 作为 A 的原型,A.__proto__ = B
// 这里让 currentInstance.provides 继承父实例的 provides,是为了不让父实例的 provides 被修改
provides = currentIsntance.provides = Object.create(parentProvides);
}
provides[key] = value;
}
}
inject
// runtime-core/apiInject.ts
export function inject(key, defaultValue) {
// 取
const currentIsntance: any = getCurrentInstance();
if(currentIsntance) {
const parentProvides = currentIsntance.parent.provides;
// 沿着 parentProvides 的原型链找,在父节点找到,便返回父节点的,
// 父节点没有再往父节点的父节点上找,原型链原理
if(key in parentProvides) {
return parentProvides[key];
} else if(defaultValue) {
if(typeof defaultValue === 'function') {
return defaultValue();
} else {
return defaultValue;
}
}
}
}
补全函数的 parentComponent 参数
// runtime-core/renderer.ts
function render(vnode, container) {
patch(vnode, container, null);
}
function patch(vnode, container, parentComponent) {}
function processComponent(vnode, container, parentComponent) {
mountComponent(vnode, container, parentComponent);
}
function mountComponent(initialVNode, container, parentComponent) {
// 创建组件实例 instance
const instance = createComponentInstance(initialVNode, parentComponent);
}
function processFragment(vnode, container, parentComponent) {
mountFragment(vnode, container, parentComponent);
}
function mountFragment(vnode, container, parentComponent) {
mountChildren(vnode, container, parentComponent);
}
function processElement(vnode, container, parentComponent) {
mountElement(vnode, container, parentComponent)
}
function mountElement(vnode, container, parentComponent) {}
function mountChildren(vnode, container, parentComponent) {
vnode.children.forEach(v => {
patch(v, conatiner, parentComponent);
});
}
function setupRenderEffect(instance, initialVNode, container) {
patch(ubTree, container, instance);
}
导出 API
// runtime-core/index.ts
export { getCurrentInstance } from './component';
export { provide, inject } from './apiInject';