目录
为什么要使用插槽?
来一起看看原因
<!-- 这是父组件 father.vue 的内容 -->
<template>
<div class='app-container'>
<son>
<p>这是父组件想要放到子组件里面的内容</p>
</son>
</div>
</template>
<script>
import son from './son';
export default {
components: {
son
},
};
</script>
<!-- 这是子组件 son.vue 的内容 -->
<template>
<div class='app-container'>
<p>这是一个子组件--start--</p>
<p>这是一个子组件--end--</p>
</div>
</template>
虽然我们在<son></son>标签内部加入了一段HTML代码,但是在渲染的过程中,这段代码是不会显示的。渲染结果如下:
总结:
正常情况下,父组件调用子组件是没问题的。但是如果父组件调用子组件需要往子组件插入内容,就需要用到插槽,否则插入内容无效
匿名插槽
如果按上面的例子往子组件中放入匿名插槽
很显然,父组件插入的内容显示出来了。所以,如果需要在父组件往调用的子组件当中插入内容。使用插槽是很有用的
具名插槽
看完匿名插槽的简单使用,再来看看具名插槽
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>具名插槽</title>
</head>
<body>
<div id="app">
<!-- 3.使用子组件 -->
<App></App>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>
<script>
// 只要匹配到slot标签的name值 template中的内容就会被插入到这个槽中
Vue.component('MBtn', {
template: `
<button>
<slot name='submit'></slot>
<slot name='login'></slot>
<slot name='register'></slot>
</button>
`
})
const App = {
data() {
return {
title: "老爹"
}
},
template: `
<div>
<m-btn>
<template slot='submit'>
提交
</template>
</m-btn>
<m-btn>
<template slot='login'>
<a href="#">登录</a>
</template>
</m-btn>
<m-btn>
<template slot='register'>
注册
</template>
</m-btn>
</div>
`,
}
new Vue({
el: '#app',
data: {
},
components: {
// 2.挂载子组件
App
}
})
</script>
</body>
</html>
看看效果:
作用域插槽
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<!-- 3.使用子组件 -->
<App></App>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>
<script>
// 已经开发了一个待办事项列表的组件,很多模块都在
// A B
// 1.之前数据格式和引用接口不变,正常显示
// 2.新功能模块增加对勾
const todoList = {
data() {
return {
}
},
props: {
todos: Array,
defaultValue: []
},
template: `
<ul>
<li v-for='item in todos' :key='item.id'>
<slot :row='item'>
</slot>
{{item.title}}
</li>
</ul>
`
}
const App = {
data() {
return {
todoList: [{
title: '大哥你好么',
isComplate: true,
id: 1
},
{
title: '小弟我还行',
isComplate: false,
id: 2
},
{
title: '你在干什么',
isComplate: false,
id: 3
},
{
title: '抽烟喝酒烫头',
isComplate: true,
id: 4
}
]
}
},
components: {
todoList
},
template: `
<todoList :todos='todoList'>
<template v-slot='{row}'>
<input type="checkbox" v-model='row.isComplate' />
</template>
</todoList>
`,
}
new Vue({
el: '#app',
data: {
},
components: {
App
}
})
</script>
</body>
</html>
以下是效果图
编译作用域
父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。
默认的插槽内容
顾名思义就是在子组件添加默认插槽内容,父组件默认传入这些内容
<!-- 这是父组件 father.vue 的内容 -->
<template>
<div class='app-container'>
<son>
<!-- 父组件什么都不传入 -->
</son>
</div>
</template>
<script>
import son from './son';
export default {
components: {
son
},
};
</script>
<!-- 这是子组件 son.vue 的内容 -->
<template>
<div class='app-container'>
<p>这是一个子组件--start--</p>
<button>
<slot>默认为submit按钮</slot>
</button>
<p>这是一个子组件--end--</p>
</div>
</template>
效果图:
访问slot
通过this.$slots.name获取具名插槽
this.$slots是vue里面的一个只读的api,用来访问被插槽分发的内容。每个具名插槽有其相应的 property (例如:v-slot:foo 中的内容将会在 vm.$slots.foo 中被找到)。default property 包括了所有没有被包含在具名插槽中的节点,或 v-slot:default 的内容。
this.$slots其实会去寻找DOM元素对应的插槽,只有在mounted的阶段,DOM才被挂载成功。
<!-- 子组件 son.vue -->
<template>
<div class='app-container'>
<p>这是一个子组件--start--</p>
<slot name="header">123</slot>
<slot name="footer">123</slot>
<slot></slot>
<p>这是一个子组件--end--</p>
</div>
</template>
<script>
export default {
//只有在Dom加载完毕之后才能使用this.$slots获取到相应插槽
mounted() {
console.log(this.$slots); // Object 所有的slot
console.log(this.$slots.header); // 获取name=header的slot
console.log(this.$slots.footer);
console.log(this.$slots.default); // 获取所有具名slot之外的slot
}
};
</script>
插槽内容其实挺简单的,就是有点绕。梳理一下就行,学习愉快!