基础用法
标签<slot>会把组件使用上下文的内容注入到此标签所占据的位置上。组件分发的概念简单而强大,因为它意味着对一个隔离的组件除了通过属性、事件交互之外,还可以注入内容。
尽管内容分发这个概念看起来极为复杂,而实际上可以简单了解为把HTML标签传入组件的一种方法。所以归根结底,内容分发是一种为组件传递参数的方法。
<div class="" id="app">
<my-component>
<p>hi,slots</p>
</my-component>
</div>
<script>
Vue.component('my-component', {
template:'<div><slot></slot><div>'
});
new Vue({
el: "#app"
});
</script>
编译作用域
组件作用域简单地说是:父组件模板的内容在父组件作用域内编译;子组件模板的内容在子组件作用域内编译。
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8"/>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<child-component v-show="someChildProperty"></child-component>
</div>
<script>
Vue.component('child-component', {
template: '<div>这是子组件内容</div>',
data: function () {
return {
someChildProperty: true
}
}
})
new Vue({
el:'#app'
})
</script>
</body>
</html>
这里someChildProperty绑定的是父组件的数据,所以是无效的,获取不到数据。如果想在子组件上绑定,可以是如下代码:
因此,slot分发的内容是在父作用域内编译。
<div id="app">
<child-component ></child-component>
</div>
<script>
Vue.component('child-component', {
// 有效,因为是在正确的作用域内
template: '<div v-show="someChildProperty">这是子组件内容</div>',
data: function () {
return {
someChildProperty: true
}
}
})
new Vue({
el:'#app'
})
</script>
默认 slot
如果要父组件在子组件中插入内容 ,必须要在子组件中声明slot 标签 ,如果子组件模板不包含<slot>插口,父组件的内容将会被丢弃
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8"/>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 1.2 那组件innerHTML位置以后不管有任何代码,都会被放进插槽那个坑里面去 -->
<index>
<span>首页</span>
<span>首页</span>
<span>首页</span>
<h1>手机</h1>
</index>
</div>
<script>
// 插槽的作用就是组件外部取代码片段放到组件内部来
// 定义默认插槽通过slot组件定义,定义好了之后,就相当于一个坑,你可以把它理解为电脑上usb插口
Vue.component('index', {
template:' <div>index</div>'
})
var vm = new Vue({
el: '#app',
})
</script>
</body>
</html>
页面显示结果为:index。所有子组件中的内容都不会被显示,被丢弃。
要想父组件在 子组件中插入内容,必须要在子组件中声明 slot 标签,示例代码如下:
<script>
vue. component ( 'index', {
template : '<div><slot></slot>index </div>'
})
var vm=new vue ( {
el : '#app ' ,
})
</script>
具名 slot
slot 元素可以用一个特殊的属性 name 来配置如何分发内容。多个 slot 标签可以有不同的名字。
使用方法。
父组件要在分发的标签中添加属性"slot=name 名"。
子组件在对应分发位置上的 slot 标签添加属性"name=name 名"。
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8"/>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<body>
<div id="app">
<child>
<span slot="one">123456</span>
<span slot="two">abcdef</span>
</child>
</div>
<script>
new Vue({
el:'#app',
components:{
child:{
template:"<div><slot name='two'></slot>我是子组件<slot name='one'></slot></div>"
}
}
});
</script>
</body>
</body>
</html>
作用域插槽
作用域插槽的样式由父组件决定,内容却由子组件控制。
作用域插槽更具代表性的应用是列表组件,允许组件自定义应该如何渲染列表每一项,如下面示例代码:
<div id="app">
<child></child>
</div>
<script>
Vue.component('child', {
data(){
return {
list:[1,2,3,4]
}
},
template: '<div> <ul>' +
'<li v-for="item of list">{{item}}</li></ul></div>',
})
var vm = new Vue({
el: '#app'
})
</script>
在上面示例代码中,如果需要child组件在很多地方会被调用,我希望在不同的地方调用child的组件时,这个列表到底怎么循环,列表的样式不是child组件控制的,而是外部child模版占位符告诉我们组件的每一项该如何渲染,也就是说这里不用li标签,而是要用slot标签,示例代码如下:
<div id="app">
<child>
<template slot-scope="props"> <!--固定写法,属性值可以自定义-->
<li>{{props.item}}</li> <!--用插值表达式就可以直接使用-->
</template>
</child>
</div>
<script>
Vue.component('child', {
data(){
return {
list:[1,2,3,4]
}
},
template: '<div> <ul>' +
'<slot v-for="item of list" :item=item></slot> </ul></div>',
})
var vm = new Vue({
el: '#app'
})
</script>