@@ -16,13 +16,12 @@ function createVNodes (
16
16
) {
17
17
var el = vueTemplateCompiler . compileToFunctions ( ( "<div>" + slotValue + "</div>" ) ) ;
18
18
var _staticRenderFns = vm . _renderProxy . $options . staticRenderFns ;
19
- // version < 2.5
20
- if ( ! vm . _renderProxy . _staticTrees ) {
21
- vm . _renderProxy . _staticTrees = [ ] ;
22
- }
19
+ var _staticTrees = vm . _renderProxy . _staticTrees ;
20
+ vm . _renderProxy . _staticTrees = [ ] ;
23
21
vm . _renderProxy . $options . staticRenderFns = el . staticRenderFns ;
24
22
var vnode = el . render . call ( vm . _renderProxy , vm . $createElement ) ;
25
23
vm . _renderProxy . $options . staticRenderFns = _staticRenderFns ;
24
+ vm . _renderProxy . _staticTrees = _staticTrees ;
26
25
return vnode . children
27
26
}
28
27
@@ -34,6 +33,9 @@ function createVNodesForSlot (
34
33
var vnode ;
35
34
if ( typeof slotValue === 'string' ) {
36
35
var vnodes = createVNodes ( vm , slotValue ) ;
36
+ if ( vnodes . length > 1 ) {
37
+ return vnodes
38
+ }
37
39
vnode = vnodes [ 0 ] ;
38
40
} else {
39
41
vnode = vm . $createElement ( slotValue ) ;
@@ -190,6 +192,12 @@ function isPlainObject (obj) {
190
192
return Object . prototype . toString . call ( obj ) === '[object Object]'
191
193
}
192
194
195
+ function isRequiredComponent ( name ) {
196
+ return (
197
+ name === 'KeepAlive' || name === 'Transition' || name === 'TransitionGroup'
198
+ )
199
+ }
200
+
193
201
//
194
202
195
203
function compileTemplate ( component ) {
@@ -297,10 +305,14 @@ function createBlankStub (
297
305
}
298
306
299
307
return Object . assign ( { } , getCoreProperties ( componentOptions ) ,
300
- { render : function render ( h ) {
308
+ { render : function render ( h , context ) {
301
309
return h (
302
310
tagName ,
303
- ! componentOptions . functional && this . $slots . default
311
+ {
312
+ attrs : componentOptions . functional ? Object . assign ( { } , context . props ,
313
+ context . data . attrs ) : Object . assign ( { } , this . $props )
314
+ } ,
315
+ context ? context . children : this . $slots . default
304
316
)
305
317
} } )
306
318
}
@@ -424,8 +436,8 @@ function requiresTemplateCompiler (slot) {
424
436
if ( typeof slot === 'string' && ! vueTemplateCompiler . compileToFunctions ) {
425
437
throwError (
426
438
"vueTemplateCompiler is undefined, you must pass " +
427
- "precompiled components if vue-template-compiler is " +
428
- "undefined"
439
+ "precompiled components if vue-template-compiler is " +
440
+ "undefined"
429
441
) ;
430
442
}
431
443
}
@@ -507,27 +519,22 @@ function getVueTemplateCompilerHelpers () {
507
519
names . forEach ( function ( name ) {
508
520
helpers [ name ] = vue . _renderProxy [ name ] ;
509
521
} ) ;
522
+ helpers . $createElement = vue . _renderProxy . $createElement ;
510
523
return helpers
511
524
}
512
525
513
526
function validateEnvironment ( ) {
514
- if ( window . navigator . userAgent . match ( / P h a n t o m J S / i) ) {
515
- throwError (
516
- "the scopedSlots option does not support PhantomJS. " +
517
- "Please use Puppeteer, or pass a component."
518
- ) ;
519
- }
520
- if ( vueVersion < 2.5 ) {
521
- throwError ( "the scopedSlots option is only supported in " + "[email protected] +." ) ;
527
+ if ( vueVersion < 2.1 ) {
528
+ throwError ( "the scopedSlots option is only supported in [email protected] +." ) ;
522
529
}
523
530
}
524
531
525
- function validateTempldate ( template ) {
526
- if ( template . trim ( ) . substr ( 0 , 9 ) === '<template' ) {
527
- throwError (
528
- "the scopedSlots option does not support a template " +
529
- "tag as the root element."
530
- ) ;
532
+ var slotScopeRe = / < [ ^ > ] + s l o t - s c o p e = \" ( . + ) \" / ;
533
+
534
+ // Hide warning about <template> disallowed as root element
535
+ function customWarn ( msg ) {
536
+ if ( msg . indexOf ( 'Cannot use <template> as component root element' ) === - 1 ) {
537
+ console . error ( msg ) ;
531
538
}
532
539
}
533
540
@@ -540,28 +547,35 @@ function createScopedSlots (
540
547
}
541
548
validateEnvironment ( ) ;
542
549
var helpers = getVueTemplateCompilerHelpers ( ) ;
543
- var loop = function ( name ) {
544
- var template = scopedSlotsOption [ name ] ;
545
- validateTempldate ( template ) ;
546
- var render = vueTemplateCompiler . compileToFunctions ( template ) . render ;
547
- var domParser = new window . DOMParser ( ) ;
548
- var _document = domParser . parseFromString ( template , 'text/html' ) ;
549
- var slotScope = _document . body . firstChild . getAttribute (
550
- 'slot-scope'
551
- ) ;
552
- var isDestructuring = isDestructuringSlotScope ( slotScope ) ;
553
- scopedSlots [ name ] = function ( props ) {
550
+ var loop = function ( scopedSlotName ) {
551
+ var slot = scopedSlotsOption [ scopedSlotName ] ;
552
+ var isFn = typeof slot === 'function' ;
553
+ // Type check to silence flow (can't use isFn)
554
+ var renderFn = typeof slot === 'function'
555
+ ? slot
556
+ : vueTemplateCompiler . compileToFunctions ( slot , { warn : customWarn } ) . render ;
557
+
558
+ var hasSlotScopeAttr = ! isFn && slot . match ( slotScopeRe ) ;
559
+ var slotScope = hasSlotScopeAttr && hasSlotScopeAttr [ 1 ] ;
560
+ scopedSlots [ scopedSlotName ] = function ( props ) {
554
561
var obj ;
555
562
556
- if ( isDestructuring ) {
557
- return render . call ( Object . assign ( { } , helpers , props ) )
563
+ var res ;
564
+ if ( isFn ) {
565
+ res = renderFn . call ( Object . assign ( { } , helpers ) , props ) ;
566
+ } else if ( slotScope && ! isDestructuringSlotScope ( slotScope ) ) {
567
+ res = renderFn . call ( Object . assign ( { } , helpers , ( obj = { } , obj [ slotScope ] = props , obj ) ) ) ;
568
+ } else if ( slotScope && isDestructuringSlotScope ( slotScope ) ) {
569
+ res = renderFn . call ( Object . assign ( { } , helpers , props ) ) ;
558
570
} else {
559
- return render . call ( Object . assign ( { } , helpers , ( obj = { } , obj [ slotScope ] = props , obj ) ) )
571
+ res = renderFn . call ( Object . assign ( { } , helpers , { props : props } ) ) ;
560
572
}
573
+ // res is Array if <template> is a root element
574
+ return Array . isArray ( res ) ? res [ 0 ] : res
561
575
} ;
562
576
} ;
563
577
564
- for ( var name in scopedSlotsOption ) loop ( name ) ;
578
+ for ( var scopedSlotName in scopedSlotsOption ) loop ( scopedSlotName ) ;
565
579
return scopedSlots
566
580
}
567
581
@@ -619,24 +633,39 @@ function createInstance (
619
633
620
634
addEventLogger ( _Vue ) ;
621
635
636
+ // Replace globally registered components with components extended
637
+ // from localVue. This makes sure the beforeMount mixins to add stubs
638
+ // is applied to globally registered components.
639
+ // Vue version must be 2.3 or greater, because of a bug resolving
640
+ // extended constructor options (https://github.com/vuejs/vue/issues/4976)
641
+ if ( vueVersion > 2.2 ) {
642
+ for ( var c in _Vue . options . components ) {
643
+ if ( ! isRequiredComponent ( c ) ) {
644
+ _Vue . component ( c , _Vue . extend ( _Vue . options . components [ c ] ) ) ;
645
+ }
646
+ }
647
+ }
648
+
622
649
var stubComponents = createComponentStubs (
623
- // $FlowIgnore
624
650
component . components ,
625
651
// $FlowIgnore
626
652
options . stubs
627
653
) ;
628
654
if ( options . stubs ) {
629
655
instanceOptions . components = Object . assign ( { } , instanceOptions . components ,
630
- // $FlowIgnore
631
656
stubComponents ) ;
632
657
}
658
+ function addStubComponentsMixin ( ) {
659
+ Object . assign (
660
+ this . $options . components ,
661
+ stubComponents
662
+ ) ;
663
+ }
633
664
_Vue . mixin ( {
634
- created : function created ( ) {
635
- Object . assign (
636
- this . $options . components ,
637
- stubComponents
638
- ) ;
639
- }
665
+ beforeMount : addStubComponentsMixin ,
666
+ // beforeCreate is for components created in node, which
667
+ // never mount
668
+ beforeCreate : addStubComponentsMixin
640
669
} ) ;
641
670
Object . keys ( componentOptions . components || { } ) . forEach ( function ( c ) {
642
671
if (
@@ -663,7 +692,9 @@ function createInstance (
663
692
component . options . _base = _Vue ;
664
693
}
665
694
666
- var Constructor = vueVersion < 2.3 && typeof component === 'function'
695
+ // when component constructed by Vue.extend,
696
+ // use its own extend method to keep component information
697
+ var Constructor = typeof component === 'function'
667
698
? component . extend ( instanceOptions )
668
699
: _Vue . extend ( component ) . extend ( instanceOptions ) ;
669
700
@@ -708,9 +739,11 @@ function createInstance (
708
739
Constructor ,
709
740
{
710
741
ref : 'vm' ,
711
- props : options . propsData ,
712
742
on : options . listeners ,
713
- attrs : options . attrs ,
743
+ attrs : Object . assign ( { } , options . attrs ,
744
+ // pass as attrs so that inheritAttrs works correctly
745
+ // propsData should take precedence over attrs
746
+ options . propsData ) ,
714
747
scopedSlots : scopedSlots
715
748
} ,
716
749
slots
0 commit comments