Skip to content

Commit f916bcf

Browse files
committed
feat: provide/inject (close #4029)
1 parent 1861ee9 commit f916bcf

File tree

3 files changed

+153
-0
lines changed

3 files changed

+153
-0
lines changed

src/core/instance/init.js

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { initProxy } from './proxy'
44
import { initState } from './state'
55
import { initRender } from './render'
66
import { initEvents } from './events'
7+
import { initInjections } from './inject'
78
import { initLifecycle, callHook } from './lifecycle'
89
import { mergeOptions } from '../util/index'
910

@@ -42,6 +43,7 @@ export function initMixin (Vue: Class<Component>) {
4243
initRender(vm)
4344
callHook(vm, 'beforeCreate')
4445
initState(vm)
46+
initInjections(vm)
4547
callHook(vm, 'created')
4648
if (vm.$options.el) {
4749
vm.$mount(vm.$options.el)

src/core/instance/inject.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
export function initInjections (vm) {
2+
const { provide, inject } = vm.$options
3+
if (provide) {
4+
vm._provided = typeof provide === 'function'
5+
? provide.call(vm)
6+
: provide
7+
}
8+
if (inject) {
9+
const isArray = Array.isArray(inject)
10+
const keys = isArray ? inject : Object.keys(inject)
11+
for (let i = 0; i < keys.length; i++) {
12+
const key = keys[i]
13+
const provideKey = isArray ? key : inject[key]
14+
let source = vm
15+
while (source) {
16+
if (source._provided && source._provided[provideKey]) {
17+
vm[key] = source._provided[provideKey]
18+
break
19+
}
20+
source = source.$parent
21+
}
22+
}
23+
}
24+
}
+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import Vue from 'vue'
2+
3+
describe('Options provide/inject', () => {
4+
let injected
5+
const injectedComp = {
6+
inject: ['foo', 'bar'],
7+
render () {},
8+
created () {
9+
injected = [this.foo, this.bar]
10+
}
11+
}
12+
13+
beforeEach(() => {
14+
injected = null
15+
})
16+
17+
it('should work', () => {
18+
new Vue({
19+
template: `<child/>`,
20+
provide: {
21+
foo: 1,
22+
bar: 2
23+
},
24+
components: {
25+
child: {
26+
template: `<injected-comp/>`,
27+
components: {
28+
injectedComp
29+
}
30+
}
31+
}
32+
}).$mount()
33+
34+
expect(injected).toEqual([1, 2])
35+
})
36+
37+
it('should use closest parent', () => {
38+
new Vue({
39+
template: `<child/>`,
40+
provide: {
41+
foo: 1,
42+
bar: 2
43+
},
44+
components: {
45+
child: {
46+
provide: {
47+
foo: 3
48+
},
49+
template: `<injected-comp/>`,
50+
components: {
51+
injectedComp
52+
}
53+
}
54+
}
55+
}).$mount()
56+
57+
expect(injected).toEqual([3, 2])
58+
})
59+
60+
it('provide function', () => {
61+
new Vue({
62+
template: `<child/>`,
63+
data: {
64+
a: 1,
65+
b: 2
66+
},
67+
provide () {
68+
return {
69+
foo: this.a,
70+
bar: this.b
71+
}
72+
},
73+
components: {
74+
child: {
75+
template: `<injected-comp/>`,
76+
components: {
77+
injectedComp
78+
}
79+
}
80+
}
81+
}).$mount()
82+
83+
expect(injected).toEqual([1, 2])
84+
})
85+
86+
it('inject with alias', () => {
87+
const injectAlias = {
88+
inject: {
89+
baz: 'foo',
90+
qux: 'bar'
91+
},
92+
render () {},
93+
created () {
94+
injected = [this.baz, this.qux]
95+
}
96+
}
97+
98+
new Vue({
99+
template: `<child/>`,
100+
provide: {
101+
foo: 1,
102+
bar: 2
103+
},
104+
components: {
105+
child: {
106+
template: `<inject-alias/>`,
107+
components: {
108+
injectAlias
109+
}
110+
}
111+
}
112+
}).$mount()
113+
114+
expect(injected).toEqual([1, 2])
115+
})
116+
117+
it('self-inject', () => {
118+
const vm = new Vue({
119+
provide: {
120+
foo: 1
121+
},
122+
inject: ['foo']
123+
})
124+
125+
expect(vm.foo).toBe(1)
126+
})
127+
})

0 commit comments

Comments
 (0)