Vue系列入门教程(9)——插槽slot

Web前端 潘老师 2个月前 (09-06) 187 ℃ (0) 扫码查看

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>

Vue系列入门教程(9)——插槽slot
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)运行至浏览器
Vue系列入门教程(9)——插槽slot
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>

7、运行至浏览器
Vue系列入门教程(9)——插槽slot

1、具名插槽,就是给这个插槽起个名字。
在向具名插槽提供内容的时候,我们可以在一个 template元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称, v-slot一般只能用在template标签上。
template元素中的所有内容都将会被传入相应的插槽。任何没有被包裹在带有 v-slottemplate中的内容都会被视为默认插槽的内容。然而,如果你希望更明确一些,仍然可以在 template 上使用v-slot:default
2、修改Center.vuetemplate如下:

<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>

4、测试运行:
Vue系列入门教程(9)——插槽slot

提示:其实上中下布局完全没必要使用插槽去做,这里只是作为一个练习而已。

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>

7、运行至浏览器
Vue系列入门教程(9)——插槽slot

有时让插槽内容能够访问子组件中才有的数据是很有用的。例如如下案例想讲插槽中的姓替换为名字:
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数据,报错如下:
Vue系列入门教程(9)——插槽slot
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)运行发现,成功修改:
Vue系列入门教程(9)——插槽slot


版权声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系潘老师进行处理。
喜欢 (7)
请潘老师喝杯Coffee吧!】
分享 (0)
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填【保密】)
  • 网址