在视图模板中可以通过 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 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>' });
|
HTML 标准关于 slot 的描述可以参考 这里
数据环境
插入 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 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'}; } });
|
命名
通过 name 属性可以给 slot 命名。一个视图模板的声明可以包含一个默认 slot 和多个命名 slot。外层组件的元素通过 slot="name"
的属性声明,可以指定自身的插入点。
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>' });
|
注意
:外层组件的替换元素,只有在直接子元素上才能声明 slot="name"
指定自身的插入点。下面例子中的 a 元素无法被插入 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>' });
|
插槽的应用
版本
:>= 3.3.0
在 slot 声明时应用 if 或 for 指令,可以让插槽根据组件数据动态化。
if指令
下面的例子中,panel 的 hidden 属性为 true 时,panel 中默认插槽将不会渲染,仅包含 title 插槽,通过 slot 方法获取的数组长度为 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指令
下面的例子没什么用,纯粹为了演示 slot 上应用 for 指令。在后续 scoped 插槽 章节中可以看到有意义的场景。
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 插槽
如果 slot 声明中包含 s-bind 或 1 个以上 var- 数据前缀声明,该 slot 为 scoped slot。scoped slot 具有独立的 数据环境。
scoped slot 通常用于组件的视图部分期望由 外部传入视图结构,渲染过程使用组件内部数据。
注意
:scoped slot 中不支持双向绑定。
var
版本
:>= 3.3.0
var- 的 scoped 数据声明的形式为 **var-name=”expression”**。
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
slots[0].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
版本
:>= 3.6.0
s-bind 的 scoped 数据声明的形式为 **s-bind=”expression”**。
当 s-bind 和 var- 并存时,var- 将覆盖整体绑定中相应的数据项。
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
slots[0].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} ] } });
|
访问环境数据
版本
:>= 3.3.1
scoped slot 中,除了可以访问 var- 声明的数据外,还可以访问当前环境的数据。
- 使用 slot 默认内容时,可以访问组件内部环境数据
- 外层组件定义的 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 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' } });
|
动态命名
版本
:>= 3.3.1
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 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: '名'}, {name: 'email', label: '邮'} ], list: [ {name: 'errorrik', email: 'errorrik@gmail.com'}, {name: 'leeight', email: 'leeight@gmail.com'} ] } });
|
注意
:表格的视图更新在 IE 下可能存在兼容性问题。