Vue 作用域插槽

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue 作用域插槽相关的知识,希望对你有一定的参考价值。

参考技术A

vue中关于插槽的文档说明很短,语言又写的很凝练,再加上其和methods,data,computed等常用选项在使用频率、使用先后上的差别,这就有可能造成初次接触插槽的开发者容易产生“算了吧,回头再学,反正已经可以写基础组件了”的想法,于是就关闭了vue的说明文档。

实际上,插槽的概念很简单,下面通过分三部分来讲。这三部分也是按照vue说明文档的顺序来写的。

进入这三部分之前,先让还没接触过插槽的同学对什么是插槽有一个简单的概念: 插槽,也就是slot,是组件的一块HTML模板,这块模板显示不显示、以及怎样显示由父组件来决定。 实际上,一个slot最核心的两个问题在这里就点出来了,是 显示不显示 怎样显示

由于插槽是一块模板,所以,对于任何一个组件,从模板种类的角度来分,其实都可以分为 非插槽模板 插槽模板 两大类。 非插槽模板指的是 html模板 ,比如‘div、span、ul、table’这些,非插槽模板的显示与隐藏以及怎样显示由组件自身控制;插槽模板是slot,它是一个空壳子,因为它的显示与隐藏以及最后用什么样的html模板显示由父组件控制。 但是插槽显示的位置却由子组件自身决定,slot写在组件template的什么位置,父组件传过来的模板将来就显示在什么位置

首先是单个插槽, 单个插槽 是vue的官方叫法,但是其实也可以叫它默认插槽,或者与具名插槽相对,我们可以叫它匿名插槽。因为它不用设置name属性。

单个插槽可以放置在组件的任意位置,但是就像它的名字一样,一个组件中只能有一个该类插槽。相对应的,具名插槽就可以有很多个,只要名字(name属性)不同就可以了。

下面通过一个例子来展示。

父组件:

子组件:

在这个例子里,因为父组件在里面写了html模板,那么子组件的 匿名插槽 这块模板就是下面这样。也就是说,子组件的匿名插槽被使用了,是被下面这块模板使用了。

最终的渲染结果如图所示:

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

匿名插槽没有name属性,所以是匿名插槽,那么,插槽加了name属性,就变成了具名插槽。具名插槽可以在一个组件中出现N次,出现在不同的位置。下面的例子,就是一个有两个 具名插槽 单个插槽 的组件,这三个插槽被父组件用同一套css样式显示了出来,不同的是内容上略有区别。

父组件:

子组件:

显示结果如图:

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

可以看到,父组件通过html模板上的slot属性关联具名插槽。没有slot属性的html模板默认关联匿名插槽。

最后,就是我们的作用域插槽。这个稍微难理解一点。官方叫它作用域插槽,实际上,对比前面两种插槽,我们可以叫它带数据的插槽。什么意思呢,就是前面两种,都是在组件的template里面写

但是 作用域插槽要求,在slot上面绑定数据 。也就是你得写成大概下面这个样子。

我们前面说了,插槽最后显示不显示是看父组件有没有在child下面写模板,像下面那样。

写了,插槽就总得在浏览器上显示点东西,东西就是html该有的模样,没写,插槽就是空壳子,啥都没有。 OK,我们说有html模板的情况,就是父组件会往子组件插模板的情况,那到底插一套什么样的样式呢,这由父组件的html+css共同决定,但是这套样式里面的内容呢?

正因为作用域插槽绑定了一套数据,父组件可以拿来用。于是,情况就变成了这样:样式父组件说了算,但内容可以显示子组件插槽绑定的。

我们再来对比,作用域插槽跟单个插槽和具名插槽的区别,因为单个插槽和具名插槽不绑定数据,所以父组件提供的模板一般要既包括样式又包括内容,上面的例子中,你看到的文字,“菜单1”,“菜单2”都是父组件自己提供的内容;而作用域插槽,父组件只需要提供一套样式(在确实用作用域插槽绑定的数据的前提下)。

下面的例子,你就能看到,父组件提供了三种样式(分别是flex、ul、直接显示),都没有提供数据,数据使用的都是子组件插槽自己绑定的那个数组(一堆人名的那个数组)。

父组件:

子组件:

结果如图所示:

vue3插槽具名插槽作用域插槽-足够入门了!

vue3 插槽

前言

这篇文章介绍vue组件的插槽!包括:插槽概念,具名插槽,作用域插槽等等,看完不会你打我。哈哈哈,开玩笑的,不多说,上刺刀!!

1. 概念

插槽(Slot)是vue为组件的封装者提供的能力。允许开发者在封装组件时,把不确定的、希望由用户指定的部分定义为插槽。

举个栗子:

​ eg组件好比小霸王游戏机,插槽就是游戏机的插口,看用户插什么卡,就在屏幕(预留的位置)上显示出对应的游戏(内容)。

我们不能把一个游戏机就固定一个游戏,有了插槽,这就一个(游戏机)组件,可以玩(显示出)不同的游戏(用户自定义的内容)。概念不太容易理解,直接上图:

2. 插槽的基本使用

  1. 在Left里面加一个slot标签
<template>
  <div class="left-container">
    <h3>Left 组件</h3>
    <!-- 声明一个插槽区域 -->
    <!-- vue 官方规定:每一个 slot 插槽,都要有一个 name 名称 -->
    <!-- 如果省略了 slot 的 name 属性,则有一个默认名称叫做 default -->
    <slot name="default"></slot>
      <!-- 如果在slot里面放内容,那么用户在没有指定内容的时候就默认显示这里的内容,当用户指定内容的时候又会把这个替换了 -->
  </div>
</template>

2 .在app根组件使用子组件里面直接放内容即可

<template>
  <div class="app-container">
    <h1>App 根组件</h1>
    <hr />

    <div class="box">
      <!-- 渲染 Left 组件和 Right 组件 -->
      <Left>
          <!-- 默认情况下,在使用组件的时候,提供的内容都会被填充到名字为 default 的插槽之中 -->
        <p>我是插槽里面用户自定义的内容</p>
      </Left>
    </div>
  </div>
</template>

<!-- 插到指定位置使用方法如下 -->
<div class="box" style="display: none;">
      <!-- 渲染 Left 组件和 Right 组件 -->
      <Left>
        <!-- 默认情况下,在使用组件的时候,提供的内容都会被填充到名字为 default 的插槽之中 -->
        <!-- 1. 如果要把内容填充到指定名称的插槽中,需要使用 v-slot: 这个指令 -->
        <!-- 2. v-slot: 后面要跟上插槽的名字 -->
        <!-- 3. v-slot: 指令不能直接用在元素身上,必须用在 template 标签上 -->
        <!-- 4. template 这个标签,它是一个虚拟的标签,只起到包裹性质的作用,但是,不会被渲染为任何实质性的 html 元素 -->
        <!-- 5. v-slot: 指令的简写形式是 # -->
        <template #default>
          <p>这是在 Left 组件的内容区域,声明的 p 标签</p>
        </template>
      </Left>
    </div>

3.这时候插槽的内容就会显示出来啦:

3. 具名插槽(带有name的插槽)

具名插槽以及作用域插槽的基本用法

eg:这里以一个栗子来讲解:

1.子组件 Article.vue 的代码:

<template>
  <div class="article-container">
    <h3 v-color="'red'">Article 组件</h3>
    <!-- 文章的标题 -->
    <div class="header-box">
      <slot name="title"></slot>
    </div>

    <!-- 文章的内容 -->
    <div class="content-box">
      <!-- 在封装组件时,为预留的 <slot> 提供属性对应的值,这种用法,叫做 “作用域插槽” -->
      <slot name="content" msg="hello vue.js" :user="userinfo"></slot>
    </div>

    <!-- 文章的作者 -->
    <div class="footer-box">
      <slot name="author"></slot>
    </div>
  </div>
</template>

<script>
export default 
  // 首字母要大写
  name: 'Article',
  data() 
    return 
      // 用户的信息对象
      userinfo: 
        name: 'zs',
        age: 20
      
    
  

</script>

<style lang="less" scoped>
.article-container 
  > div 
    min-height: 150px;
  
  .header-box 
    background-color: pink;
  
  .content-box 
    background-color: lightblue;
  
  .footer-box 
    background-color: lightsalmon;
  

</style>

2.App.vue代码:

<template>
  <div class="app-container">
    <h1 v-color="color">App 根组件</h1>
    <p v-color="'red'">测试</p>

    <button @click="color = 'green'">改变 color 的颜色值</button>
    <hr />

    <Article>
      <template #title>
        <h3>星月看大海</h3>
      </template>

      <template #content=" msg, user ">
        <div>
          <p>啊,大海,全是水。</p>
          <p>啊,蜈蚣,全是腿。</p>
          <p>啊,辣椒,净辣嘴。</p>
          <p> msg </p>
          <p> user.name </p>
        </div>
      </template>

      <template #author>
        <div>作者:星月</div>
      </template>
    </Article>
  </div>
</template>

<script>
import Left from '@/components/Left.vue'
import Article from '@/components/Article.vue'

export default 
  data() 
    return 
      color: 'blue'
    
  ,
  components: 
    Left,
    Article
  ,
  // 私有自定义指令的节点
  directives: 
    // 定义名为 color 的指令,指向一个配置对象
    /* color: 
      // 当指令第一次被绑定到元素上的时候,会立即触发 bind 函数
      // 形参中的 el 表示当前指令所绑定到的那个 DOM 对象
      bind(el, binding) 
        console.log('触发了 v-color 的 bind 函数')
        el.style.color = binding.value
      ,
      // 在 DOM 更新的时候,会触发 update 函数
      update(el, binding) 
        console.log('触发了 v-color 的 update 函数')
        el.style.color = binding.value
      
     */
    color(el, binding) 
      el.style.color = binding.value
    
  

</script>

<style lang="less">
.app-container 
  padding: 1px 20px 20px;
  background-color: #efefef;

.box 
  display: flex;

</style>

这样就把用户在app自定义的内容通过具名插槽的方式来显示出来了。

栗子运行截图来了:

4. 作用域插槽

在封装组件的过程中,可以为预留的 < slot> 插槽绑定 props 数据,这种带有 props 数据的 < slot> 叫做“作用域插槽”。可以在父组件中传参来显示子组件绑定的数据,示例代码如下:

<!-- app.vue中使用自定义组件 -->
<my-test>
	<template #default=" msg, info ">
		<p> msg </p>
		<p> info.address </p>
	</template>
</my-test>

<!-- 子组件中预留的 < slot> 插槽绑定 props 数据 -->
<template>
  <div>
    <h3>这是 TEST 组件</h3>
    <slot :info="infomation" :msg="message"></slot>
  </div>
</template>

<script>
export default 
  name: 'MyTest',
  data() 
    return 
      // 信息数据
      infomation: 
        phone: '152xxxx6666',
        address: '云南昆明',
      ,
      message: 'abc'
    
  ,

</script>

4.1 解构作用域插槽的 Prop

作用域插槽对外提供的数据对象,可以使用解构赋值简化数据的接收过程。示例代码如下:

    <!-- 使用自定义组件 -->
<my-test>
    <!-- 解构 msg, info  ,这样在使用的时候就不用去scope.info,或者scope.msg 了。 -->
 <template #default=" msg, info ">
   <p> msg </p>
   <p> info.address </p>
 </template>
</my-test>

4.2 声明以及使用作用域插槽

在封装 MyTable 组件的过程中,可以通过作用域插槽把表格每一行的数据传递给组件的使用者。在使用 MyTable 组件时,自定义单元格的渲染方式,并接收作用域插槽对外提供的数据。示例代码如下:

<!-- 在app中使用这个组件,以及传递参数 -->
<my-table>
    <template #default=" user ">
      <td> user.id </td>
      <td> user.name </td>
      <td>
        <input type="checkbox" :checked="user.state" />
      </td>
    </template>
</my-table>

<!-- 自定义的作用域插槽组件 -->
<template>
  <table class="table table-bordered table-striped table-dark table-hover">
    <!-- 表头区域 -->
    <thead>
      <tr>
        <th>Id</th>
        <th>Name</th>
        <th>State</th>
      </tr>
    </thead>
    <!-- 表格主体区域 -->
    <tbody>
      <!-- 循环渲染表格数据 -->
      <tr v-for="item in list" :key="item.id">
        <slot :user="item"></slot>
      </tr>
    </tbody>
  </table>
</template>

<script>
export default 
  name: 'MyTable',
  data() 
    return 
      // 列表的数据
      list: [
         id: 1, name: '张三', state: true ,
         id: 2, name: '李四', state: false ,
         id: 3, name: '赵六', state: false ,
      ],
    
  ,

</script>

<style lang="less" scoped></style>

写在最后

✨个人笔记博客✨

星月前端博客
http://blog.yhxweb.top/

✨原创不易,还希望各位大佬支持一下

👍 点赞,你的认可是我创作的动力!

⭐️ 收藏,你的青睐是我努力的方向!

✏️评论,你的意见是我进步的财富!

以上是关于Vue 作用域插槽的主要内容,如果未能解决你的问题,请参考以下文章

[vue3进阶] 6.slot插槽3——作用域插槽

细说Vue作用域插槽,匹配应用场景。

语法糖&具名插槽&作用域插槽&混入

Vue-作用域插槽-列表组件

vue 作用域插槽

Vue.js 源码分析(二十六) 高级应用 作用域插槽 详解