10.插槽

95 阅读2分钟

在某些组件的模板中,有一部分区域需要父组件来指定,类似于iOS里面现在自定义的控件里面,调用某个方法需要传一个UIView进去一样。

<!-- message组件:一个弹窗消息 -->
<div class="message-container">
  <div class="content">
    <!-- 这里是消息内容,可以是一个文本,也可能是一段html,具体是什么不知道,需要父组件指定 -->
  </div>
  <button>确定</button>
  <button>关闭</button>
</div>

插槽的简单用法

此时,就需要使用插槽来定制组件的功能

<!-- message组件:一个弹窗消息 -->
<div class="message-container">
  <div class="content">
    <!-- slot是vue的内置组件 -->
    <slot></slot>
  </div>
  <button>确定</button>
  <button>关闭</button>
</div>

<!-- 父组件App -->
<Message>
	<div class="app-message">
    <p>App Message</p>
    <a href="">detail</a>
  </div>
</Message>

<!-- 最终的结果 -->
<div class="message-container">
  <div class="content">
    <div class="app-message">
      <p>App Message</p>
      <a href="">detail</a>
    </div>
  </div>
  <button>确定</button>
  <button>关闭</button>
</div>
image-20201202152326210

具名插槽

如果某个组件中需要父元素传递多个区域的内容,也就意味着需要提供多个插槽

为了避免冲突,就需要给不同的插槽赋予不同的名字。简单来说就是一共三个插槽,三个插槽怎么对应呢,起个名字吧,就叫具名插槽。

<!-- Layout 组件 -->
<div class="layout-container">
  <header>
    <!-- 我们希望把页头放这里,提供插槽,名为header -->
    <slot name="header"></slot>
  </header>
  <main>
    <!-- 我们希望把主要内容放这里,提供插槽,名为default -->
    <slot></slot>
  </main>
  <footer>
    <!-- 我们希望把页脚放这里,提供插槽,名为footer -->
    <slot name="footer"></slot>
  </footer>
</div>

<!-- 父组件App -->
<BaseLayout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>

  <template v-slot:default>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  <template v-slot:default>
    
  <template v-slot:footer>
    <p>Here's some contact info</p>
  </template>
</BaseLayout>
image-20201202153229391

代码 这里的示例就是示例项目的左右结构进行完成。

这是使用的代码

<template>
  <div class="test-container">
    <Layout>
      <div class="main">
        主区域,宽度占满剩余空间,溢出隐藏主区域,宽度占满剩余空间,溢出隐藏主区域,宽度占满剩余空间,溢出隐藏主区域,宽度占满剩余空间,溢出隐藏主区域,宽度占满剩余空间,溢出隐藏主区域,宽度占满剩余空间,溢出隐藏主区域,宽度占满剩余空间,溢出隐藏主区域,宽度占满剩余空间,溢出隐藏主区域,宽度占满剩余空间,溢出隐藏主区域,宽度占满剩余空间,溢出隐藏主区域,宽度占满剩余空间,溢出隐藏主区域,宽度占满剩余空间,溢出隐藏主区域,宽度占满剩余空间,溢出隐藏
      </div>
      <template #right>
        <div class="right">
          右边栏区域,宽度适应内容,溢出隐藏
        </div>
      </template>
    </Layout>
  </div>
</template>

<script>
import Layout from "./";
export default {
  components: {
    Layout,
  },
};
</script>

<style scoped>
.test-container {
  width: 60%;
  height: 600px;
  border: 2px solid;
  margin: 0 auto;
  white-space: nowrap;
}
.left {
  width: 200px;
  height: 100%;
  background: lightcoral;
}
.main {
  width: 100%;
  height: 100%;
  background: lightseagreen;
}
.right {
  width: 150px;
  height: 100%;
  background: lightblue;
}
</style>

1.v-slot: 可以简写为#

下面是组件代码

<template>
  <div class="layout-container">
    <div class="left">
      <slot name="left"></slot>
    </div>
    <div class="main">
      <slot></slot>
    </div>
    <div class="right">
      <slot name="right"></slot>
    </div>
  </div>
</template>

<script>
export default {};
</script>

<style scoped lang="less">
.layout-container {
  width: 100%;
  height: 100%;
  display: flex;
  .left,
  .right {
    flex: 0 0 auto;
    overflow: hidden;
  }
  .main {
    flex: 1 1 auto;
    overflow: hidden;
  }
}
</style>

作用域插槽

说在作用域插槽内,父组件可以拿到子组件的数据。子组件可以在slot标签上绑定属性值,如:

<slot :nickName="'Tusi'"></slot>

而父组件通过slot-scope绑定的对象下拿到nickName的值。

<template>
    <section>
        <slot-child>
            <template slot-scope="scope">
                <div>{{scope.nickName}}</div>
            </template>
        </slot-child>
    </section>
</template>