为什么要使用插槽
我们先写一个父组件向子组件传标签的代码
<body>
<div id="root">
<child content='<p>world</p>'></child>
</div>
<script type="text/javascript">
Vue.component('child',{
props:['content'],
template:'<div> <p>hello</p> {{content}} </div>'
})
var vm =new Vue({
el:'#root',
})
</script>
</body>
这里显示的是传递进来的HTML标签,并没有进行渲染。
所以我们将模板修改为:
template:'<div> <p>hello</p> <div v-html="this.content"></div> </div>'
这样做的缺点首先是需要在外面写一个<div>盒子进行包裹。其次,若content内容较多时,比较难阅读。
插槽
什么是插槽
语法:<slot></slot>
作用:将父组件前后标签中的HTML文件渲染插入模板中使用。
接下来我们使用插槽来实现同样的功能。
<body>
<div id="root">
<child>
<h1>world</h1>
</child>
</div>
<script type="text/javascript">
Vue.component('child',{
template:'<div> <p>hello</p> <slot></slot> </div>'
})
var vm =new Vue({
el:'#root',
})
</script>
</body>
顾名思义,插槽就是将父组件插入的部分传入模板中进行使用。
插槽的一些用法
- 当使用<slot></slot>标签,但是父组件中没有插入html代码时,标签内的代码将被渲染。
<body>
<div id="root">
<child></child>
</div>
<script type="text/javascript">
Vue.component('child',{
template:'<div> <p>hello</p> <slot><h1>world</h1></slot> </div>'
})
var vm =new Vue({
el:'#root',
})
</script>
</body>
- 使组件内容由子组件设定和外部传入组成
我们希望这个模板由父组件提供页头和页脚,其余部分由自身模板决定。
<body>
<div id="root">
<child>
<div class="header">header</div>
<div class="footer">footer</div>
</child>
</div>
<script type="text/javascript">
Vue.component('child',{
template:`<div>
<slot></slot>
<div class='content'>content</div>
<slot></slot>
</div>`
})
var vm =new Vue({
el:'#root',
})
</script>
</body>
<<插一句:这里使用的ES6的写法来进行换行书写模板,实现效果不变,但是看着更清晰。>>
出现第一个和第二个<slot>标签都显示了整个插槽俩内容。
当然我们需要让他们一一对应,所以我们给插槽取名字变成具名插槽:
<child>
<div class="header" slot="header">header</div>
<div class="footer" slot="footer">footer</div>
</child>
使用时也按名用:
Vue.component('child',{
template:`<div>
<slot name='header'></slot>
<div class='content'>content</div>
<slot name='footer'></slot>
</div>`
})
其余部分不变
- 找不到具名插槽时以默认值为内容
这里我们将上面代码的第一个插槽去掉
<body>
<div id="root">
<child>
<div class="footer" slot="footer">footer</div>
</child>
</div>
<script type="text/javascript">
Vue.component('child',{
template:`<div>
<slot name='header'>找不到!</slot>
<div class='content'>content</div>
<slot name='footer'></slot>
</div>`
})
var vm =new Vue({
el:'#root',
})
</script>
</body>
作用域插槽
准备代码
我们先写一个子组件,并实现循环输出列表内容的效果
<body>
<div id="root">
<child></child>
</div>
<script type="text/javascript">
Vue.component('child',{
data:function(){
return{
list:[1,2,3,4]
}
},
template:`<div>
<ul>
<li v-for="item of list">{{item}}</li>
</ul>
</div>`
})
var vm =new Vue({
el:'#root',
})
</script>
</body>
实现外部控制形式的功能
我们现在希望能实现由外部决定循环输出数组的格式,而不是都按<li>输出。
- 首先修改子组件模板内部为插槽形式:
使用 <slot> 语句,并将item值绑定在val上
template:`<div>
<ul>
<slot v-for="item of list" :val=item>
</slot>
</ul>
</div>`
- 父组件中写作用域插槽
作用域插槽必须是一个<template>开头和结尾的内容
<child>
<template slot-scope="props">
</template>
</child>
在<child>中套一个 <template></template> ,这是固定写法,同时需要在前标签中写入slot-scope="props"
,意为子组件的值储存在"prop"中,此处“props”仅仅是个属性名字,可以自己定义,其作用是接受子组件中的绑定值。
- 将从子组件获取的值使用
<child>
<template slot-scope="props">
<h1>it's {{props.item}}</h1>
</template>
</child>
这样效果就完成了
- 完整代码:
<body>
<div id="root">
<child>
<template slot-scope="props">
<h1>it's {{props.val}}</h1>
</template>
</child>
</div>
<script type="text/javascript">
Vue.component('child',{
data:function(){
return{
list:[1,2,3,4]
}
},
template:`<div>
<ul>
<slot v-for="item of list" :val=item>
</slot>
</ul>
</div>`
})
var vm =new Vue({
el:'#root',
})
</script>
</body>
最后完整捋一遍
首先将子组件写成插槽,然后将子组件中储存的值绑定在val上,我们在外部组件(父组件)上写slot-scope="props"
,使子组件上绑着的 val(来自list的item数据)储存在父组件定义的属性 "props"中,并通过props.val
使用。
然后我们在父组件中说明以某种形式展示子组件存储在list内的值,并传递给插槽。