Skip to content

Commit f6857af

Browse files
author
lishiwen
committed
feat: basic provide/inject
1 parent cf715c7 commit f6857af

File tree

12 files changed

+197
-65
lines changed

12 files changed

+197
-65
lines changed

example/provide-inject/App.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { h } from "../../lib/m-vue.esm.js";
2+
import Provider from "./Provider.js";
3+
4+
export default {
5+
render() {
6+
return h(Provider);
7+
},
8+
setup() {},
9+
};

example/provide-inject/Consumer.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { h, inject } from "../../lib/m-vue.esm.js";
2+
3+
export default {
4+
name: "Consumer",
5+
6+
render() {
7+
return h("span", {}, `inject value: ${this.bar}`);
8+
},
9+
10+
setup() {
11+
const bar = inject("bar");
12+
13+
return {
14+
bar,
15+
};
16+
},
17+
};

example/provide-inject/Provider.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { h, provide } from "../../lib/m-vue.esm.js";
2+
import Consumer from "./Consumer.js";
3+
4+
export default {
5+
name: "Provider",
6+
7+
render() {
8+
return h("div", {}, [h(Consumer)]);
9+
},
10+
11+
setup() {
12+
provide("count", 10);
13+
provide("bar", "bar");
14+
},
15+
};

example/provide-inject/index.html

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>Provide</title>
8+
</head>
9+
<body>
10+
<div id="app"></div>
11+
</body>
12+
<script src="./main.js" type="module"></script>
13+
</html>

example/provide-inject/main.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { createApp } from "../../lib/m-vue.esm.js";
2+
import App from "./App.js";
3+
4+
createApp(App).mount(document.getElementById("app"));

lib/m-vue.cjs.js

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -236,14 +236,16 @@ var instanceRuntimeExtendApis = /*#__PURE__*/Object.freeze({
236236
});
237237

238238
let currentInstance = null;
239-
function createComponentInstance(vnode) {
239+
function createComponentInstance(vnode, parent) {
240240
// instance
241241
const component = {
242242
vnode,
243243
type: vnode.type,
244244
setupState: {},
245245
props: {},
246246
slots: {},
247+
parent,
248+
provides: {},
247249
emit: (instance, event) => { },
248250
};
249251
// 官方Emit
@@ -296,42 +298,42 @@ function clearCurrentInstance() {
296298
currentInstance = null;
297299
}
298300

299-
function render(vnode, container) {
300-
patch(vnode, container);
301+
function render(vnode, container, parentComponent) {
302+
patch(vnode, container, parentComponent);
301303
}
302-
function patch(vnode, container) {
304+
function patch(vnode, container, parentComponent) {
303305
switch (vnode === null || vnode === void 0 ? void 0 : vnode.type) {
304306
case Fragment:
305-
processFragment(vnode, container);
307+
processFragment(vnode, container, parentComponent);
306308
break;
307309
case Text:
308310
processText(vnode, container);
309311
break;
310312
default:
311313
if (vnode.shapeFlag & 1 /* ShapeFlags.ELEMENT */) {
312-
processElement(vnode, container);
314+
processElement(vnode, container, parentComponent);
313315
}
314316
if (vnode.shapeFlag & 2 /* ShapeFlags.STATEFUL_COMPONENT */) {
315-
processComponent(vnode, container);
317+
processComponent(vnode, container, parentComponent);
316318
}
317319
break;
318320
}
319321
}
320-
function processElement(vnode, container) {
321-
mountElement(vnode, container);
322+
function processElement(vnode, container, parentComponent) {
323+
mountElement(vnode, container, parentComponent);
322324
}
323-
function processComponent(vnode, container) {
324-
mountComponent(vnode, container);
325+
function processComponent(vnode, container, parentComponent) {
326+
mountComponent(vnode, container, parentComponent);
325327
}
326-
function processFragment(vnode, container) {
327-
mountChildren(vnode === null || vnode === void 0 ? void 0 : vnode.children, container);
328+
function processFragment(vnode, container, parentComponent) {
329+
mountChildren(vnode === null || vnode === void 0 ? void 0 : vnode.children, container, parentComponent);
328330
}
329-
function mountComponent(initialVNode, container) {
330-
const instance = createComponentInstance(initialVNode);
331+
function mountComponent(initialVNode, container, parentComponent) {
332+
const instance = createComponentInstance(initialVNode, parentComponent);
331333
setupComponent(instance);
332334
setupRenderEffect(instance, container, initialVNode);
333335
}
334-
function mountElement(vnode, container) {
336+
function mountElement(vnode, container, parentComponent) {
335337
// vnode type -> div/span
336338
// vnode.el -> element.el
337339
const el = (vnode.el = document.createElement(vnode.type));
@@ -340,16 +342,16 @@ function mountElement(vnode, container) {
340342
el.textContent = vnode.children;
341343
}
342344
else if (vnode.shapeFlag & 8 /* ShapeFlags.ARRAY_CHILDREN */) {
343-
mountChildren(vnode.children, el);
345+
mountChildren(vnode.children, el, parentComponent);
344346
}
345347
// props
346348
addAttrs(vnode, el);
347349
// append to container
348350
container.appendChild(el);
349351
}
350-
function mountChildren(children = [], container) {
352+
function mountChildren(children = [], container, parentComponent) {
351353
children.forEach(child => {
352-
patch(child, container);
354+
patch(child, container, parentComponent);
353355
});
354356
}
355357
function isOnEvent(propertyName) {
@@ -375,7 +377,7 @@ function addAttrs(vnode, container) {
375377
function setupRenderEffect(instance, container, initialVNode) {
376378
var _a;
377379
const subTree = (_a = instance === null || instance === void 0 ? void 0 : instance.render) === null || _a === void 0 ? void 0 : _a.call(instance.proxy);
378-
patch(subTree, container);
380+
patch(subTree, container, instance);
379381
initialVNode.el = subTree.el;
380382
}
381383
function processText(vnode, container) {
@@ -388,7 +390,7 @@ function createApp(rootComponent) {
388390
mount(rootContainer) {
389391
// 转vNode, 基于vNode工作
390392
const vnode = createVNode(rootComponent);
391-
render(vnode, rootContainer);
393+
render(vnode, rootContainer, undefined);
392394
}
393395
};
394396
}
@@ -411,14 +413,37 @@ function renderSlots(slots, renderName, props = {}) {
411413
}
412414
}
413415

416+
/**
417+
* Notes:
418+
* 1. instance只能在setup中调用, 故使得provide工/inject作的作用域仅为setup
419+
*/
420+
function provide(key, value) {
421+
const currentInstance = getCurrentInstance();
422+
if (currentInstance) {
423+
mountProvide(currentInstance === null || currentInstance === void 0 ? void 0 : currentInstance.provides, key, value);
424+
}
425+
}
426+
function mountProvide(target, key, value) {
427+
target[key] = value;
428+
}
429+
function inject(key) {
430+
const currentInstance = getCurrentInstance();
431+
if (currentInstance) {
432+
const parentProvides = currentInstance.parent.provides;
433+
return parentProvides[key];
434+
}
435+
}
436+
414437
exports.clearCurrentInstance = clearCurrentInstance;
415438
exports.createApp = createApp;
416439
exports.createComponentInstance = createComponentInstance;
417440
exports.createTextVNode = createTextVNode;
418441
exports.createVNode = createVNode;
419442
exports.getCurrentInstance = getCurrentInstance;
420443
exports.h = h;
444+
exports.inject = inject;
421445
exports.patch = patch;
446+
exports.provide = provide;
422447
exports.render = render;
423448
exports.renderSlots = renderSlots;
424449
exports.setCurrentInstance = setCurrentInstance;

lib/m-vue.esm.js

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -232,14 +232,16 @@ var instanceRuntimeExtendApis = /*#__PURE__*/Object.freeze({
232232
});
233233

234234
let currentInstance = null;
235-
function createComponentInstance(vnode) {
235+
function createComponentInstance(vnode, parent) {
236236
// instance
237237
const component = {
238238
vnode,
239239
type: vnode.type,
240240
setupState: {},
241241
props: {},
242242
slots: {},
243+
parent,
244+
provides: {},
243245
emit: (instance, event) => { },
244246
};
245247
// 官方Emit
@@ -292,42 +294,42 @@ function clearCurrentInstance() {
292294
currentInstance = null;
293295
}
294296

295-
function render(vnode, container) {
296-
patch(vnode, container);
297+
function render(vnode, container, parentComponent) {
298+
patch(vnode, container, parentComponent);
297299
}
298-
function patch(vnode, container) {
300+
function patch(vnode, container, parentComponent) {
299301
switch (vnode === null || vnode === void 0 ? void 0 : vnode.type) {
300302
case Fragment:
301-
processFragment(vnode, container);
303+
processFragment(vnode, container, parentComponent);
302304
break;
303305
case Text:
304306
processText(vnode, container);
305307
break;
306308
default:
307309
if (vnode.shapeFlag & 1 /* ShapeFlags.ELEMENT */) {
308-
processElement(vnode, container);
310+
processElement(vnode, container, parentComponent);
309311
}
310312
if (vnode.shapeFlag & 2 /* ShapeFlags.STATEFUL_COMPONENT */) {
311-
processComponent(vnode, container);
313+
processComponent(vnode, container, parentComponent);
312314
}
313315
break;
314316
}
315317
}
316-
function processElement(vnode, container) {
317-
mountElement(vnode, container);
318+
function processElement(vnode, container, parentComponent) {
319+
mountElement(vnode, container, parentComponent);
318320
}
319-
function processComponent(vnode, container) {
320-
mountComponent(vnode, container);
321+
function processComponent(vnode, container, parentComponent) {
322+
mountComponent(vnode, container, parentComponent);
321323
}
322-
function processFragment(vnode, container) {
323-
mountChildren(vnode === null || vnode === void 0 ? void 0 : vnode.children, container);
324+
function processFragment(vnode, container, parentComponent) {
325+
mountChildren(vnode === null || vnode === void 0 ? void 0 : vnode.children, container, parentComponent);
324326
}
325-
function mountComponent(initialVNode, container) {
326-
const instance = createComponentInstance(initialVNode);
327+
function mountComponent(initialVNode, container, parentComponent) {
328+
const instance = createComponentInstance(initialVNode, parentComponent);
327329
setupComponent(instance);
328330
setupRenderEffect(instance, container, initialVNode);
329331
}
330-
function mountElement(vnode, container) {
332+
function mountElement(vnode, container, parentComponent) {
331333
// vnode type -> div/span
332334
// vnode.el -> element.el
333335
const el = (vnode.el = document.createElement(vnode.type));
@@ -336,16 +338,16 @@ function mountElement(vnode, container) {
336338
el.textContent = vnode.children;
337339
}
338340
else if (vnode.shapeFlag & 8 /* ShapeFlags.ARRAY_CHILDREN */) {
339-
mountChildren(vnode.children, el);
341+
mountChildren(vnode.children, el, parentComponent);
340342
}
341343
// props
342344
addAttrs(vnode, el);
343345
// append to container
344346
container.appendChild(el);
345347
}
346-
function mountChildren(children = [], container) {
348+
function mountChildren(children = [], container, parentComponent) {
347349
children.forEach(child => {
348-
patch(child, container);
350+
patch(child, container, parentComponent);
349351
});
350352
}
351353
function isOnEvent(propertyName) {
@@ -371,7 +373,7 @@ function addAttrs(vnode, container) {
371373
function setupRenderEffect(instance, container, initialVNode) {
372374
var _a;
373375
const subTree = (_a = instance === null || instance === void 0 ? void 0 : instance.render) === null || _a === void 0 ? void 0 : _a.call(instance.proxy);
374-
patch(subTree, container);
376+
patch(subTree, container, instance);
375377
initialVNode.el = subTree.el;
376378
}
377379
function processText(vnode, container) {
@@ -384,7 +386,7 @@ function createApp(rootComponent) {
384386
mount(rootContainer) {
385387
// 转vNode, 基于vNode工作
386388
const vnode = createVNode(rootComponent);
387-
render(vnode, rootContainer);
389+
render(vnode, rootContainer, undefined);
388390
}
389391
};
390392
}
@@ -407,4 +409,25 @@ function renderSlots(slots, renderName, props = {}) {
407409
}
408410
}
409411

410-
export { clearCurrentInstance, createApp, createComponentInstance, createTextVNode, createVNode, getCurrentInstance, h, patch, render, renderSlots, setCurrentInstance, setupComponent };
412+
/**
413+
* Notes:
414+
* 1. instance只能在setup中调用, 故使得provide工/inject作的作用域仅为setup
415+
*/
416+
function provide(key, value) {
417+
const currentInstance = getCurrentInstance();
418+
if (currentInstance) {
419+
mountProvide(currentInstance === null || currentInstance === void 0 ? void 0 : currentInstance.provides, key, value);
420+
}
421+
}
422+
function mountProvide(target, key, value) {
423+
target[key] = value;
424+
}
425+
function inject(key) {
426+
const currentInstance = getCurrentInstance();
427+
if (currentInstance) {
428+
const parentProvides = currentInstance.parent.provides;
429+
return parentProvides[key];
430+
}
431+
}
432+
433+
export { clearCurrentInstance, createApp, createComponentInstance, createTextVNode, createVNode, getCurrentInstance, h, inject, patch, provide, render, renderSlots, setCurrentInstance, setupComponent };

src/runtime-core/component.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@ let currentInstance = null;
1111
// NOTE: 这是自己扩展的
1212
import * as instanceRuntimeExtendApis from "./instanceRuntimeExtends";
1313

14-
export function createComponentInstance(vnode) {
14+
export function createComponentInstance(vnode, parent) {
1515
// instance
1616
const component = {
1717
vnode,
1818
type: vnode.type,
1919
setupState: {},
2020
props: {},
2121
slots: {},
22+
parent,
23+
provides: {},
2224
emit: (instance, event) => { },
2325
};
2426

src/runtime-core/createApp.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export function createApp(rootComponent) {
66
mount(rootContainer) {
77
// 转vNode, 基于vNode工作
88
const vnode = createVNode(rootComponent);
9-
render(vnode, rootContainer)
9+
render(vnode, rootContainer, undefined)
1010
}
1111
}
1212
}

src/runtime-core/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ export * from "./createVNode";
33
export * from "./component";
44
export * from "./render";
55
export * from "./h"
6-
export * from "./helper/renderSlots";
6+
export * from "./helper/renderSlots";
7+
export * from "./inject"

0 commit comments

Comments
 (0)