插槽分为:匿名插槽、具名插槽和作用域插槽。
组件是可复用的,但是不可能所有地方使用某个组件时都是相同的,比如说按钮,现在希望登录按钮中包含一个a标签,注册按钮就是单纯的一个按钮,但它们使用同一个按钮组件来实现。这个时候就需要用到插槽,在
template模板中通过slot标签留槽,后期在使用组件时就可以填入自己想要的内容。
匿名插槽
定义一个全局的button组件MBtn,在template模板中加上<slot></slot>留槽,使用时往该组件中写入想要的内容会自动插入到slot这个槽中。
注意:该组件的命名在使用时可以直接写<MBtn></MBtn>,也可以<m-btn></m-btn>这样写。
<body>
<div id="app">
<App></App>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
Vue.component('MBtn', {
template: `
<button>
<slot></slot>
</button>
`
})
const App = {
template: `
<div>
<m-btn><a href="#">登录</a></m-btn>
<m-btn>注册</m-btn>
</div>
`
}
new Vue({
el: '#app',
components: {
App
}
})
</script>
</body>
具名插槽
具名插槽就是在通过slot标签留槽的时候给它一个name属性命名用于区分。但是在使用的时候稍有不同,需要在组件标签中嵌套一个<template></template>,同时给它一个slot属性,该属性中填写的就是希望匹配的<slot></slot>的name名。
注意:最后按钮显示的结果顺序与MBtn组件的插槽顺序无关,取决于App模板中的填充顺序,最先是提交按钮,然后是登录按钮,最后是注册按钮,在浏览器上也是这个显示顺序,而这个顺序与插槽的定义顺序并不一致。
<body>
<div id="app">
<App></App>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
Vue.component('MBtn', {
template: `
<button>
<slot name='login'></slot>
<slot name='register'></slot>
<slot name='submit'></slot>
</button>
`
})
const App = {
template: `
<div>
<m-btn>
<template slot='submit'>
提交
</template>
</m-btn>
<m-btn>
<template slot='login'>
登录
</template>
</m-btn>
<m-btn>
<template slot='register'>
注册
</template>
</m-btn>
</div>
`
}
new Vue({
el: '#app',
components: {
App
}
})
</script>
</body>
作用域插槽
场景:已经开发了一个待办事项列表组件,很多模块都在使用。 要求:
- 之前数据格式和引用接口不变,正常显示
- 新功能模块增加对勾(已完成的事项打✔)
首先在todolist的模板中添加<slot></slot>插槽,并在其上绑定需要传回给父组件的数据(这些数据会封装成一个对象),然后在父组件中通过v-slot来接收。
<body>
<div id="app">
<App></App>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const todolist = {
props: {
//接收一个数组
todos: Array,
//默认空数组
defaultValue: []
},
//在slot上将当前每一项的数据绑定,在父组件中通过v-slot接收
template: `
<ul>
<li v-for='item in todos' :key='item.id'>
<slot :itemValue='item'>
</slot>
{{item.title}}
</li>
</ul>
`
}
const App = {
data() {
return {
todoList: [{
id: 1,
title: `散步`,
isComplete: true
}, {
id: 2,
title: '打电话',
isComplete: true
}, {
id: 3,
title: '玩游戏',
isComplete: false
}, {
id: 4,
title: '洗澡',
isComplete: true
}, {
id: 5,
title: '睡觉',
isComplete: false
}]
}
},
components: {
todolist
},
template: `
<todolist :todos='todoList'>
<template v-slot='data'>
<input type='checkbox' v-model='data.itemValue.isComplete'>
</template>
</todolist>
`
}
new Vue({
el: '#app',
components: {
App
}
})
</script>
</body>