Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
forked fromvuejs/vue

Commitea0d227

Browse files
committed
feat: functional component support for compiled templates
1 parent68bdbf5 commitea0d227

File tree

5 files changed

+162
-53
lines changed

5 files changed

+162
-53
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*@flow */
2+
3+
import{toNumber,toString,looseEqual,looseIndexOf}from'shared/util'
4+
import{createTextVNode,createEmptyVNode}from'core/vdom/vnode'
5+
import{renderList}from'./render-list'
6+
import{renderSlot}from'./render-slot'
7+
import{resolveFilter}from'./resolve-filter'
8+
import{checkKeyCodes}from'./check-keycodes'
9+
import{bindObjectProps}from'./bind-object-props'
10+
import{renderStatic,markOnce}from'./render-static'
11+
import{bindObjectListeners}from'./bind-object-listeners'
12+
import{resolveScopedSlots}from'./resolve-slots'
13+
14+
exportfunctioninstallRenderHelpers(target:any){
15+
target._o=markOnce
16+
target._n=toNumber
17+
target._s=toString
18+
target._l=renderList
19+
target._t=renderSlot
20+
target._q=looseEqual
21+
target._i=looseIndexOf
22+
target._m=renderStatic
23+
target._f=resolveFilter
24+
target._k=checkKeyCodes
25+
target._b=bindObjectProps
26+
target._v=createTextVNode
27+
target._e=createEmptyVNode
28+
target._u=resolveScopedSlots
29+
target._g=bindObjectListeners
30+
}

‎src/core/instance/render-helpers/render-static.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,14 @@ export function renderStatic (
99
index:number,
1010
isInFor?:boolean
1111
):VNode|Array<VNode>{
12-
let tree=this._staticTrees[index]
12+
// static trees can be rendered once and cached on the contructor options
13+
// so every instance shares the same trees
14+
let options=this.constructor.options
15+
if(this.$options.staticRenderFns!==options.staticRenderFns){
16+
options=this.$options
17+
}
18+
consttrees=options._staticTrees||(options._staticTrees=[])
19+
lettree=trees[index]
1320
// if has already-rendered static tree and not inside v-for,
1421
// we can reuse the same tree by doing a shallow clone.
1522
if(tree&&!isInFor){
@@ -18,8 +25,8 @@ export function renderStatic (
1825
:cloneVNode(tree)
1926
}
2027
// otherwise, render a fresh tree.
21-
tree=this._staticTrees[index]=
22-
this.$options.staticRenderFns[index].call(this._renderProxy)
28+
tree=trees[index]=
29+
options.staticRenderFns[index].call(this._renderProxy,null,this)
2330
markStatic(tree,`__static__${index}`,false)
2431
returntree
2532
}

‎src/core/instance/render.js

Lines changed: 7 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,18 @@
33
import{
44
warn,
55
nextTick,
6-
toNumber,
7-
toString,
8-
looseEqual,
96
emptyObject,
107
handleError,
11-
looseIndexOf,
128
defineReactive
139
}from'../util/index'
1410

15-
importVNode,{
16-
cloneVNodes,
17-
createTextVNode,
18-
createEmptyVNode
19-
}from'../vdom/vnode'
11+
import{createElement}from'../vdom/create-element'
12+
import{installRenderHelpers}from'./render-helpers/index'
13+
import{resolveSlots}from'./render-helpers/resolve-slots'
14+
importVNode,{cloneVNodes,createEmptyVNode}from'../vdom/vnode'
2015

2116
import{isUpdatingChildComponent}from'./lifecycle'
2217

23-
import{createElement}from'../vdom/create-element'
24-
import{renderList}from'./render-helpers/render-list'
25-
import{renderSlot}from'./render-helpers/render-slot'
26-
import{resolveFilter}from'./render-helpers/resolve-filter'
27-
import{checkKeyCodes}from'./render-helpers/check-keycodes'
28-
import{bindObjectProps}from'./render-helpers/bind-object-props'
29-
import{renderStatic,markOnce}from'./render-helpers/render-static'
30-
import{bindObjectListeners}from'./render-helpers/bind-object-listeners'
31-
import{resolveSlots,resolveScopedSlots}from'./render-helpers/resolve-slots'
32-
3318
exportfunctioninitRender(vm:Component){
3419
vm._vnode=null// the root of the child tree
3520
vm._staticTrees=null
@@ -65,6 +50,9 @@ export function initRender (vm: Component) {
6550
}
6651

6752
exportfunctionrenderMixin(Vue:Class<Component>){
53+
// install runtime convenience helpers
54+
installRenderHelpers(Vue.prototype)
55+
6856
Vue.prototype.$nextTick=function(fn:Function){
6957
returnnextTick(fn,this)
7058
}
@@ -135,23 +123,4 @@ export function renderMixin (Vue: Class<Component>) {
135123
vnode.parent=_parentVnode
136124
returnvnode
137125
}
138-
139-
// internal render helpers.
140-
// these are exposed on the instance prototype to reduce generated render
141-
// code size.
142-
Vue.prototype._o=markOnce
143-
Vue.prototype._n=toNumber
144-
Vue.prototype._s=toString
145-
Vue.prototype._l=renderList
146-
Vue.prototype._t=renderSlot
147-
Vue.prototype._q=looseEqual
148-
Vue.prototype._i=looseIndexOf
149-
Vue.prototype._m=renderStatic
150-
Vue.prototype._f=resolveFilter
151-
Vue.prototype._k=checkKeyCodes
152-
Vue.prototype._b=bindObjectProps
153-
Vue.prototype._v=createTextVNode
154-
Vue.prototype._e=createEmptyVNode
155-
Vue.prototype._u=resolveScopedSlots
156-
Vue.prototype._g=bindObjectListeners
157126
}

‎src/core/vdom/create-functional-component.js

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import VNode from './vnode'
44
import{createElement}from'./create-element'
55
import{resolveInject}from'../instance/inject'
66
import{resolveSlots}from'../instance/render-helpers/resolve-slots'
7+
import{installRenderHelpers}from'../instance/render-helpers/index'
78

89
import{
910
isDef,
@@ -12,15 +13,43 @@ import {
1213
validateProp
1314
}from'../util/index'
1415

16+
functionFunctionalRenderContext(
17+
data,
18+
props,
19+
children,
20+
parent,
21+
Ctor
22+
){
23+
constoptions=Ctor.options
24+
this.data=data
25+
this.props=props
26+
this.children=children
27+
this.parent=parent
28+
this.listeners=data.on||emptyObject
29+
this.injections=resolveInject(options.inject,parent)
30+
this.slots=()=>resolveSlots(children,parent)
31+
// support for compiled functional template
32+
if(options._compiled){
33+
this.constructor=Ctor
34+
this.$options=options
35+
this._c=parent._c
36+
this.$slots=this.slots()
37+
this.$scopedSlots=data.scopedSlots||emptyObject
38+
}
39+
}
40+
41+
installRenderHelpers(FunctionalRenderContext.prototype)
42+
1543
exportfunctioncreateFunctionalComponent(
1644
Ctor:Class<Component>,
1745
propsData: ?Object,
1846
data:VNodeData,
19-
context:Component,
47+
contextVm:Component,
2048
children: ?Array<VNode>
2149
):VNode|void{
50+
const options=Ctor.options
2251
constprops={}
23-
constpropOptions=Ctor.options.props
52+
constpropOptions=options.props
2453
if(isDef(propOptions)){
2554
for(constkeyinpropOptions){
2655
props[key]=validateProp(key,propOptions,propsData||emptyObject)
@@ -31,20 +60,19 @@ export function createFunctionalComponent (
3160
}
3261
// ensure the createElement function in functional components
3362
// gets a unique context - this is necessary for correct named slot check
34-
const_context=Object.create(context)
35-
consth=(a,b,c,d)=>createElement(_context,a,b,c,d,true)
36-
constvnode=Ctor.options.render.call(null,h,{
63+
const_contextVm=Object.create(contextVm)
64+
consth=(a,b,c,d)=>createElement(_contextVm,a,b,c,d,true)
65+
constrenderContext=newFunctionalRenderContext(
3766
data,
3867
props,
3968
children,
40-
parent:context,
41-
listeners:data.on||emptyObject,
42-
injections:resolveInject(Ctor.options.inject,context),
43-
slots:()=>resolveSlots(children,context)
44-
})
69+
contextVm,
70+
Ctor
71+
)
72+
constvnode=options.render.call(null,h,renderContext)
4573
if(vnodeinstanceofVNode){
46-
vnode.functionalContext=context
47-
vnode.functionalOptions=Ctor.options
74+
vnode.functionalContext=contextVm
75+
vnode.functionalOptions=options
4876
if(data.slot){
4977
(vnode.data||(vnode.data={})).slot=data.slot
5078
}

‎test/unit/features/options/functional.spec.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,4 +185,79 @@ describe('Options functional', () => {
185185
constvnode=h('child')
186186
expect(vnode).toEqual(createEmptyVNode())
187187
})
188+
189+
it('should work with render fns compiled from template',done=>{
190+
// code generated via vue-template-es2015-compiler
191+
varrender=function(_h,_vm){
192+
var_c=_vm._c
193+
return_c(
194+
'div',
195+
[
196+
_c('h2',{staticClass:'red'},[_vm._v(_vm._s(_vm.props.msg))]),
197+
_vm._t('default'),
198+
_vm._t('slot2'),
199+
_vm._t('scoped',null,{msg:_vm.props.msg}),
200+
_vm._m(0),
201+
_c('div',{staticClass:'clickable',on:{click:_vm.parent.fn}},[
202+
_vm._v('click me')
203+
])
204+
],
205+
2
206+
)
207+
}
208+
varstaticRenderFns=[
209+
function(_h,_vm){
210+
var_c=_vm._c
211+
return_c('div',[_vm._v('Some '),_c('span',[_vm._v('text')])])
212+
}
213+
]
214+
215+
constchild={
216+
functional:true,
217+
_compiled:true,
218+
render,
219+
staticRenderFns
220+
}
221+
222+
constparent=newVue({
223+
components:{
224+
child
225+
},
226+
data:{
227+
msg:'hello'
228+
},
229+
template:`
230+
<div>
231+
<child :msg="msg">
232+
<span>{{ msg }}</span>
233+
<div slot="slot2">Second slot</div>
234+
<template slot="scoped" slot-scope="scope">{{ scope.msg }}</template>
235+
</child>
236+
</div>
237+
`,
238+
methods:{
239+
fn(){
240+
this.msg='bye'
241+
}
242+
}
243+
}).$mount()
244+
245+
functionassertMarkup(){
246+
expect(parent.$el.innerHTML).toBe(
247+
`<div>`+
248+
`<h2 class="red">${parent.msg}</h2>`+
249+
`<span>${parent.msg}</span> `+
250+
`<div>Second slot</div>`+
251+
parent.msg+
252+
// static
253+
`<div>Some <span>text</span></div>`+
254+
`<div class="clickable">click me</div>`+
255+
`</div>`
256+
)
257+
}
258+
259+
assertMarkup()
260+
triggerEvent(parent.$el.querySelector('.clickable'),'click')
261+
waitForUpdate(assertMarkup).then(done)
262+
})
188263
})

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp