1、插槽内容官方文档:https://cn.vuejs.org/v2/guide/components-slots.html
2、什么是插槽?
插槽就是子组件中的提供给父组件使用的一个占位符,用<slot></slot>
表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的<slot></slot>
标签。
3、插槽作用
插槽就是Vue实现的一套内容分发的API,可以分发内容,<slot></slot>
元素作为承载分发内容的出口,这句话的意思就是,没有插槽的情况下在组件标签内部一些内容是不起任何作用的,当我在组件中声明了slot元素后,在组件元素内写的内容就会跑到它这里了!
1、<slot></slot>
元素有一个特殊的属性:name
。这个属性可以用来定义插槽的名称,一个不带 name 的 <slot></slot>
出口会带有隐含的名字“default”,我们称为“默认插槽”。
2、我们来实现一个代码案例:
1)在components
中新建Loading.vue
组件(这里演示我们用条形效果):
条形效果:
<!-- Loding组件——条形效果--> <template> <div class="loading"> <span></span> <span></span> <span></span> <span></span> <span></span> </div> </template> <style scoped> .loading{ width: 80px; height: 40px; margin: 0 auto; margin-top:100px; } .loading span{ display: inline-block; width: 8px; height: 100%; border-radius: 4px; background: lightgreen; margin-left: 5px; -webkit-animation: load 1.04s ease infinite; } @-webkit-keyframes load{ 0%,100%{ height: 40px; background: lightgreen; } 50%{ height: 60px; margin-top: -20px; background: lightblue; } } .loading span:nth-child(2){ -webkit-animation-delay:0.13s; } .loading span:nth-child(3){ -webkit-animation-delay:0.26s; } .loading span:nth-child(4){ -webkit-animation-delay:0.39s; } .loading span:nth-child(5){ -webkit-animation-delay:0.52s; } </style>
圆形效果:
<!-- Loding组件——圆形效果 --> <template> <div class="loadEffect"> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> </div> </template> <style scoped> .loadEffect{ width: 100px; height: 100px; position: relative; margin: 0 auto; margin-top:100px; } .loadEffect span{ display: inline-block; width: 16px; height: 16px; border-radius: 50%; background: lightgreen; position: absolute; -webkit-animation: load 1.04s ease infinite; } @-webkit-keyframes load{ 0%{ opacity: 1; } 100%{ opacity: 0.2; } } .loadEffect span:nth-child(1){ left: 0; top: 50%; margin-top:-8px; -webkit-animation-delay:0.13s; } .loadEffect span:nth-child(2){ left: 14px; top: 14px; -webkit-animation-delay:0.26s; } .loadEffect span:nth-child(3){ left: 50%; top: 0; margin-left: -8px; -webkit-animation-delay:0.39s; } .loadEffect span:nth-child(4){ top: 14px; right:14px; -webkit-animation-delay:0.52s; } .loadEffect span:nth-child(5){ right: 0; top: 50%; margin-top:-8px; -webkit-animation-delay:0.65s; } .loadEffect span:nth-child(6){ right: 14px; bottom:14px; -webkit-animation-delay:0.78s; } .loadEffect span:nth-child(7){ bottom: 0; left: 50%; margin-left: -8px; -webkit-animation-delay:0.91s; } .loadEffect span:nth-child(8){ bottom: 14px; left: 14px; -webkit-animation-delay:1.04s; } </style>
2)在components
中新建Center.vue
组件,用于显示网站中间内容(不过中间内容不确定,可能是各种其他组件,因此我们使用插槽):
<template> <div class="center"> <!-- 模板中某个位置,无法确定具体内容 --> <!-- 使用插槽-默认插槽 slot中可以填写默认内容,如果没有组件插入时显示,有插入时则被替换--> <slot></slot> </div> </template> <style scoped> .center { position: fixed; left: 50%; top:50%; transform: translate(-50%,-50%); } </style>
3)App.vue
:
<template> <div id="app"> <Center> <!-- 在Center组件内部使用Laoding组件会加载到Center的默认插槽 --> <Loading/> </Center> </div> </template> <script> import Center from './components/Center.vue' import Loading1 from './components/Loading.vue' export default { name: 'app', components: { Center, Loading } } </script> <style> </style>
4)运行至浏览器
5)插槽用的比较多的就是我们上面的居中Center.vue和蒙层,下面我们再来创建个蒙层Modal.vue
:
<template> <div class="modal"> <slot></slot> </div> </template> <style scoped> .modal{ z-index: 999; position: fixed; top: 0; bottom: 0; left: 0; right: 0; background-color: rgba(55,55,55,.5); height: 100%; } </style>
6)实现加载条在蒙层中居中显示,修改App.vue
:
<template> <div id="app"> <Modal> <Center> <Loading/> </Center> </Modal> </div> </template> <script> import Center from './components/Center.vue' import Loading from './components/Loading.vue' import Modal from './components/Modal.vue' export default { name: 'app', components: { Center, Loading, Modal } } </script> <style> </style>
3、修改Center.vue
:
<template> <div class="center"> <!-- 模板中某个位置,无法确定具体内容 --> <!-- 使用插槽-默认插槽--> <slot></slot> <!-- 使用插槽-具名插槽--> <slot name="Loading2"></slot> </div> </template> <style scoped> /* 注释掉居中样式,否则两个加载组件会重叠 .center { position: fixed; left: 50%; top:50%; transform: translate(-50%,-50%); } */ </style>
1、具名插槽,就是给这个插槽起个名字。
在向具名插槽提供内容的时候,我们可以在一个 template
元素上使用 v-slot
指令,并以 v-slot
的参数的形式提供其名称, v-slot
一般只能用在template
标签上。
template
元素中的所有内容都将会被传入相应的插槽。任何没有被包裹在带有 v-slot
的template
中的内容都会被视为默认插槽的内容。然而,如果你希望更明确一些,仍然可以在 template
上使用v-slot:default
2、修改Center.vue
的template
如下:
<template> <div class="center"> <!-- 这里面的内容不确定,因此我们可以使用插槽 默认插槽,没有指定name,默认名称为default--> <slot></slot> <!-- 具名插槽 --> <slot name="slot1"></slot> <slot name="slot2"></slot> <slot name="loading"></slot> </div> </template>
3、修改App.vue的template如下:
<template> <div id="app"> <Center> <h1>兄弟们,快去填坑,我先填默认坑</h1> <template v-slot:slot1> <div> 我是slot1模板,我去填slot1这个坑 </div> </template> <template v-slot:slot2> <div> 我是slot2模板,我去填slot2这个坑 </div> </template> <!-- 插槽中填组件,放在template模板中 --> <template v-slot:loading> <Loading></Loading> </template> </Center> </div> </template>
1、在
components
中新建Header.vue
组件:
<template> <!-- 头部菜单 --> <div class="header"> <a href="/">首页</a> <a href="/blog">博客</a> <a href="/about">关于我们</a> </div> </template> <script> export default { } </script> <style scoped> .header { width:1000px; margin:0 auto; height:80px; background:black; display:flex; justify-content: center; align-items:center; } .header a{ font-size:18px; text-decoration: none; color:white; margin:0 10px; } </style>
3、在components
中新建Home.vue
组件:
<template> <div> 这里是首页内容 </div> </template> <script> export default { } </script> <style scoped> </style>
4、在components
中新建Footer.vue
组件:
<template> <div class="footer"> 底部区域 </div> </template> <script> export default { } </script> <style scoped> .footer{ width:1000px; line-height:80px; background: gray; margin:0 auto; text-align:center; color:white; } </style>
5、在components
中新建Index.vue
组件:
<template> <div class="container"> <!-- 具名插槽,名称为header --> <slot name="header"></slot> <!-- 默认插槽,默认名称default --> <slot></slot> <!-- 具名插槽,名称为footer --> <slot name="footer"></slot> </div> </template> <style scoped> .container{ border: 1px solid gray; margin:30px auto; width:1000px; min-height: 200px; } </style>
6、修改App.vue
<template> <div id="app"> <!-- 将对应的名称的组件插入到对应的Index的插槽中 --> <Index> <template v-slot:header> <Header></Header> </template> <Home v-slot:default></Home> <template v-slot:footer> <Footer></Footer> </template> </Index> </div> </template> <script> // 导入组件 import Index from './components/Index.vue' import Header from './components/Header.vue' import Footer from './components/Footer.vue' import Home from './components/Home.vue' export default { name: 'app', components: { // 注册组件 Index, Header, Footer, Home, } } </script> <style> .container{ border: 1px solid gray; margin:30px auto; width:1000px; min-height: 200px; } </style>
有时让插槽内容能够访问子组件中才有的数据是很有用的。例如如下案例想讲插槽中的姓替换为名字:
1)在components
中新建CurrentUser.vue
组件:
<template> <div> <span> <!-- 插槽内容默认为姓 --> <slot>{{user.firstName}}</slot> </span> </div> </template> <script> export default { data(){ return { user:{ firstName:"潘", lastName:"子夜" } } } } </script> <style scoped> </style>
2)修改App.vue
如下,想将姓换为对应的名字:
<template> <div id="app"> <CurrentUser> <!-- 替换插槽内容为名字 --> {{user.lastName}} </CurrentUser> </div> </template> <script> // 导入组件 import CurrentUser from './components/CurrentUser.vue' export default { name: 'app', components: { // 注册组件 CurrentUser } } </script> <style> .container{ border: 1px solid gray; margin:30px auto; width:1000px; min-height: 200px; } </style>
3)运行发现,根本无法实现,因为App.vue
中根本无法访问子组件CurrentUser
中的user
数据,报错如下:
4)为了让 user
在父级的插槽内容中可用,我们可以将 user
作为 slot
元素的一个属性绑定上去,修改CurrentUser.vue
中插槽代码如下:
<slot :user="user">{{user.firstName}}</slot>
5)绑定在 slot
元素上的 属性被称为插槽 prop
。现在在父级作用域中,我们可以使用带值的 v-slot
来定义我们提供的插槽 prop
的名字,修改App.vue的CurrentUser
部分代码如下:
<CurrentUser> <!-- 替换插槽内容为名字 --> <template v-slot:default="slotProps"> {{slotProps.user.lastName}} </template> </CurrentUser>
在这个例子中,我们选择将包含所有插槽 prop
的对象命名为 slotProps
,但你也可以使用任意你喜欢的名字。
6)运行发现,成功修改: