Templates can contain slots, the contents in which position can be defined by its parent component.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 var Panel = san.defineComponent ({ template : '<div>' + ' <div class="head" on-click="toggle">title</div>' + ' <p style="{{fold | yesToBe(\'display:none\')}}"><slot></slot></p>' + '</div>' , toggle : function ( ) { this .data .set ('fold' , !this .data .get ('fold' )); } }); var MyComponent = san.defineComponent ({ components : { 'ui-panel' : Panel }, template : '<div><ui-panel>Hello San</ui-panel></div>' });
Please refer to the HTML Spec for more information about slots.
Data Scope Inside a slot, the scope is the parent component’s scope .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 var Panel = san.defineComponent ({ template : '<div>' + ' <div class="head" on-click="toggle">title</div>' + ' <p><slot></slot></p>' + '</div>' , initData : function ( ) { return {name : 'Panel' }; } }); var MyComponent = san.defineComponent ({ components : { 'ui-panel' : Panel }, template : '<div><ui-panel>I am {{name}}</ui-panel></div>' , initData : function ( ) { return {name : 'MyComponent' }; } });
Named Slots Slots can be named by assigning a name attribute. A template can contain one unnamed slot and multiple named slots. By declaring the attribute slot="name"
, parent components can specify where the contents are placed in.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 var Tab = san.defineComponent ({ template : '<div>' + ' <header><slot name="title"></slot></header>' + ' <main><slot></slot></main>' + '</div>' }); var MyComponent = san.defineComponent ({ components : { 'ui-tab' : Tab }, template : '<div><ui-tab>' + '<h3 slot="title">1</h3><p>one</p>' + '<h3 slot="title">2</h3><p>two</p>' + '</ui-tab></div>' });
Note
: slot="name"
attribute only takes effect when specified on the direct child of the component element to be injected. The a
element will NOT be rendered into the title
slot.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 var Tab = san.defineComponent ({ template : '<div>' + ' <header><slot name="title"></slot></header>' + ' <main><slot></slot></main>' + '</div>' }); var MyComponent = san.defineComponent ({ components : { 'ui-tab' : Tab }, template : '<div><ui-tab>' + '<h3 slot="title">1</h3><p>one</p>' + '<h3 slot="title">2</h3><p>two<a slot="title">slot fail</a></p>' + '</ui-tab></div>' });
Use Cases Version
: >= 3.3.0
Slots can be used along with if
or for
directives.
if Directive In the following example, the unnamed slot won’t be rendered since the hidden
attribute for the panel is set to true. The .slot()
method returns 0
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 var Panel = san.defineComponent ({ template : '<div><slot name="title"/><slot s-if="!hidden"/></div>' , }); var MyComponent = san.defineComponent ({ components : { 'x-panel' : Panel }, template : '' + '<div>' + '<x-panel hidden="{{folderHidden}}" s-ref="panel">' + '<b slot="title">{{name}}</b>' + '<p>{{desc}}</p>' + '</x-panel>' + '</div>' , attached : function ( ) { this .ref ('panel' ).slot ().length } }); var myComponent = new MyComponent ({ data : { folderHidden : true , desc : 'MVVM component framework' , name : 'San' } });
for Directive The following case may not be useful, it’s only intended to demonstrate how to use slots along with the for
directive. There’s a real world case latter in the scoped slots section.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 var Panel = san.defineComponent ({ template : '<div><slot s-for="item in data"/></div>' , }); var MyComponent = san.defineComponent ({ components : { 'x-panel' : Panel }, template : '' + '<div>' + '<x-panel data="{{panelData}}" s-ref="panel">' + '<p>{{name}}</p>' + '</x-panel>' + '</div>' , attached : function ( ) { this .ref ('panel' ).slot ().length } }); var myComponent = new MyComponent ({ data : { panelData : [1 , 2 , 3 ], name : 'San' } });
Scoped Slots If there’s a s-bind attribute or one or more var- prefixed attributes specified, the slot is called a scoped slot.
Scoped slot is useful when the contents is expected to be rendered using external layouts with internal data.
Note
: Bi-directional binding is not supported in scoped slots.
var Version
: >= 3.3.0
A var- prefixed attribute is set in var-name=”expression” format.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 var Men = san.defineComponent ({ template : '<div>' + '<slot s-for="item in data" var-n="item.name" var-email="item.email" var-sex="item.sex ? \'male\' : \'female\'">' + '<p>{{n}},{{sex}},{{email}}</p>' + '</slot>' + '</div>' }); var MyComponent = san.defineComponent ({ components : { 'x-men' : Men }, template : '<div><x-men data="{{men}}" s-ref="men">' + '<h3>{{n}}</h3>' + '<p><b>{{sex}}</b><u>{{email}}</u></p>' + '</x-men></div>' , attached : function ( ) { var slots = this .ref ('men' ).slot (); slots.length slots[0 ].isInserted contentSlot.isScoped } }); var myComponent = new MyComponent ({ data : { men : [ {name : 'errorrik' , sex : 1 , email : 'errorrik@gmail.com' }, {name : 'leeight' , sex : 0 , email : 'leeight@gmail.com' }, {name : 'otakustay' , email : 'otakustay@gmail.com' , sex : 1 } ] } });
s-bind Version
: >= 3.6.0
A s-bind attribute is set in s-bind=”expression” format.
When both s-bind and var- attributes are set, var- attributes will hide the corresponding items in s-bind .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 var Men = san.defineComponent ({ template : '<div>' + '<slot s-for="item in data" s-bind="{n: item.name, email: item.email, sex: item.sex ? \'male\' : \'female\'}">' + '<p>{{n}},{{sex}},{{email}}</p>' + '</slot>' + '</div>' }); var MyComponent = san.defineComponent ({ components : { 'x-men' : Men }, template : '<div><x-men data="{{men}}" s-ref="men">' + '<h3>{{n}}</h3>' + '<p><b>{{sex}}</b><u>{{email}}</u></p>' + '</x-men></div>' , attached : function ( ) { var slots = this .ref ('men' ).slot (); slots.length slots[0 ].isInserted contentSlot.isScoped } }); var myComponent = new MyComponent ({ data : { men : [ {name : 'errorrik' , sex : 1 , email : 'errorrik@gmail.com' }, {name : 'leeight' , sex : 0 , email : 'leeight@gmail.com' }, {name : 'otakustay' , email : 'otakustay@gmail.com' , sex : 1 } ] } });
Scope Data Access Version
: >= 3.3.1
Besides data declared by var- , scope data is also available in scoped slots.
When the default contents is used, the internal scope is available
When the external contents is used, the external component’s scope is available
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 var Man = san.defineComponent ({ template : '<p>' + '<slot var-n="who.name" var-email="who.email">' + '{{n}},{{email}},{{country}}' + '</slot>' + '</p>' }); var MyComponent = san.defineComponent ({ components : { 'x-man' : Man }, template : '' + '<div><x-man who="{{man}}" country="{{country}}">' + '<b>{{n}} - {{province}}</b>' + '<u>{{email}}</u>' + '</x-men></div>' }); var myComponent = new MyComponent ({ data : { man : { name : 'errorrik' , email : 'errorrik@gmail.com' }, country : 'China' , province : 'HN' } });
Dynamic Naming Version
: >= 3.3.1
Slots can be named using data from the current scope to provide dynamic slots, which is useful in cases when the layouts are generated from data , for example, the table components.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 var Table = san.defineComponent ({ template : '' + '<table>' + '<thead><tr><th s-for="col in columns">{{col.label}}</th></tr></thead>' + '<tbody>' + '<tr s-for="row in datasource">' + '<td s-for="col in columns">' + '<slot name="col-{{col.name}}" var-row="row" var-col="col">{{row[col.name]}}</slot>' + '</td>' + ' </tr>' + '</tbody>' + '</table>' }); var MyComponent = san.defineComponent ({ components : { 'x-table' : Table }, template : '' + '<div>' + '<x-table columns="{{columns}}" datasource="{{list}}">' + '<b slot="col-name">{{row.name}}</b>' + '</x-table>' + '</div>' }); var myComponent = new MyComponent ({ data : { columns : [ {name : 'name' , label : 'N' }, {name : 'email' , label : 'E' } ], list : [ {name : 'errorrik' , email : 'errorrik@gmail.com' }, {name : 'leeight' , email : 'leeight@gmail.com' } ] } });
Note
: There’re compatibility issues with table updating in IE.