从组件封装看Vue的作用域插槽的实现

作用域插槽不是那么直观的一个概念。Vue文档使用了一段描述性的话来解释作用域插槽:

有的时候你希望提供的组件带有一个可从子组件获取数据的可复用的插槽
……
但是在我们应用的某些部分,我们希望每个独立的待办项渲染出和 todo.text 不太一样的东西。这也是作用域插槽的用武之地。

但在我看来,至少是第一次读到的时候,这段话相当不好理解。插槽不是分发内容到子组件吗,为什么还要从子组件中获取数据?不是已经有了通过emit事件的方法从子组件向父组件传递数据吗,为什么需要它?作用域插槽到底是来干嘛的?……

在浏览了不少博客、自己思考“如果不这么做,就会怎么样”再动手实践之后,作用域插槽的含义才逐渐明了。其实作用域插槽提供了一种封装可复用组件的新思路。下面我会从最简单的例子开始。

简单的展示列表

现在我们做一个纯展示用途的列表组件,如下图所示:

第一个例子先用slot来分发内容

<template>
 <div class="list">
  <div class="list-title">
   <slot name="title"></slot>
  </div>
  <div class="list-content">
   <slot name="content"></slot>
  </div>
 </div>
</template>

<script>
 export default {
  name: "MyList"
 }
</script>

在父组件中使用MyList

<template>
 <MyList>
  <span slot="title">title</span>
  <ul slot="content">
   <li v-for="item in listData">{{item}}</li>
  </ul>
 </MyList>
</template>

<script>
 import myList from './List.vue';
 export default {
  name: 'HelloWorld',
  components: {
   'MyList': myList
  },
  data() {
   return {
    listData: [
      '列表项1',
      '列表项2',
      '列表项3'
    ]
   }
  }
 }
</script>

省略了其中的样式代码,结果如图所示

满足了基本的需求,但是作为组件的使用者,这样的一个组件会让我觉得非常麻烦,content中循环的逻辑还需要我自己动手来写,这样的使用毫无便利性。于是有了下面第二个版本

使用prop来传递数据

因为考虑到列表的内容总是一个数组,我把循环结构写进了组件中

列表组件第二版:

<template>
 <div class="list">
  <div class="list-title">{{title}}</div>
  <ul class="list-content">
   <li v-for="(item ,index) in content" :key="index">{{item}}</li>
  </ul>
 </div>
</template>

<script>
 export default {
  name: "MyList",
  props: {
   title: {
    type: String,
    required: true
   },
   content: {
    type: Array,
    required: true
   }
  }
 }
</script>

使用起来也非常方便,只需通过prop将数据传入组件中

<template>
 <div>
  <MyList title="标题1" :content="listData"></MyList>
  <MyList title="标题2" :content="newListData"></MyList>
 </div>
</template>

<script>
 import myList from './List.vue';
 export default {
  name: 'HelloWorld',
  components: {
   'MyList': myList
  },
  data() {
   return {
    listData: [
      '列表项1',
      '列表项2',
      '列表项3'
    ],
    newListData: [
      '新的列表项1',
      '新的列表项2',
      '新的列表项3'
    ],
   }
  }
 }
</script>

改进之后,每当我使用组件只需一行代码,大大简化了工作量

易用性的需求也满足了,但现在又有了新的问题,组件的拓展性不好!每次只能生成相同结构的列表,一旦业务需求发生了变化,组件就不再适用了。比如我现在有了新的需求,在一个列表的每个列表项前加入了一个小logo,我总不可能又写一个新的组件来适应需求的变化吧?假如需要更多的定制化场景呢?

作用域插槽

这里就有了第三版的列表组件,使用作用域插槽将子组件中的数据传递出去

<template>
 <div class="list">
  <div class="list-title">{{title}}</div>
  <ul class="list-content">
   <li v-for="(item ,index) in content" :key="index">
    <!--这里将content中的每一项数据绑定到slot的item变量上,在父组件中可以获取到item变量-->
    <slot :item="item">{{item}}</slot>
   </li>
  </ul>
 </div>
</template>

使用组件时,将业务所需的content模板传入

<template>
 <div>
  <MyList title="标题1" :content="listData1"></MyList>
  <MyList title="标题2" :content="listData2">
   <template slot-scope="scope">
    <img :src="scope.item.img" width="20">
    <span>{{scope.item.text}}</span>
   </template>
  </MyList>
  <MyList title="标题3" :content="listData3">
   <template slot-scope="scope">
    <b>{{scope.item.prefix ? '有前缀' : '无前缀'}}</b>
    <span>{{scope.item.text}}</span>
    <span>{{scope.item.remark}}</span>
   </template>
  </MyList>
 </div>
</template>

<script>
 import myList from './List.vue';

 export default {
  name: 'HelloWorld',
  components: {
   'MyList': myList
  },
  data() {
   return {
    listData1: [
     '列表项1',
     '列表项2',
     '列表项3'
    ],
    listData2: [
     {text: '第二个列表的列表项1', img: 'example.png'},
     {text: '第二个列表的列表项2', img: 'example.png'},
     {text: '第二个列表的列表项3', img: 'example.png'}
    ],
    listData3: [
     {text: '第三个列表的列表项1', prefix: true, remark: '附加的备注1'},
     {text: '第三个列表的列表项2', prefix: false, remark: '附加的备注2'},
     {text: '第三个列表的列表项3', prefix: true, remark: '附加的备注3'}
    ],
   }
  }
 }
</script>

实现了定制化的列表

再回到开始的问题,作用域插槽到底是干嘛用的?很显然,它的作用就如官网所说的一样:将组件的数据暴露出去。而这么做,给了组件的使用者根据数据定制模板的机会,组件不再是写死成一种特定的结构。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 浅析vue插槽和作用域插槽的理解

    插槽: 插槽,也就是slot,是组件的一块HTML模板,这块模板显示不现实.以及怎样显示由父组件来决定. 插槽模板是slot,它是一个空壳子,因为它显示与隐藏以及最后用什么样的html模板显示由父组件控制.但是插槽显示的位置由子组件自身决定,slot写在组件template的哪块,父组件传过来的模板将来就显示在哪块.这样就使组件可复用性更高,更加灵活.我们可以随时通过父组件给子组件加一些需要的东西. 这个可以参考https://www.jb51.net/article/160047.htm.这位

  • Vue作用域插槽slot-scope实例代码

    vue中的插槽有三种:单个插槽.具名插槽.作用域插槽,这个在官网上能看到 (https://cn.vuejs.org/v2/guide/components.html#单个插槽) 作用域插槽简单来说就是父组件只管显示样式,数据由子组件来提供.比如上面的代码,el-table-column内的template是传递给其内部solt的显示内容,但是scope的值是由el-table-column内部solt绑定的数据返回的.这个数据具体是什么由el-table-column中指定,类似: <slot

  • 如何理解Vue的作用域插槽的实现原理

    本文介绍了如何理解Vue的作用域插槽的实现原理,分享给大家,也给自己留个笔记 举个例子,比如我写了一个可以实现条纹相间的列表组件,发布后,使用者可以自定义每一行的内容或样式(普通的slot就可以完成这个工作).而作用域插槽的关键之处就在于,父组件能接收来自子组件的slot传递过来的参数,具体看案例和注释. <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"

  • 详解Vue组件之作用域插槽

    写作用域插槽之前,先介绍一下Vue中的slot内容分发: 如果<child-component></child-component>标签之间没有插入那两个p标签的话,页面会显示子组件模板中定义的"<p>父组件如果没有插入内容,我将被显示</p>"这一则内容,但如果<child-component></child-component>标签之间有插入内容的话,则子组件模板中的<slot></slot&

  • Vue中的slot使用插槽分发内容的方法

    本文题材来自:https://cn.vuejs.org/v2/guide/components.html#%E4%BD%BF%E7%94%A8%E6%8F%92%E6%A7%BD%E5%88%86%E5%8F%91%E5%86%85%E5%AE%B9 <slot></slot>标签,简单来说就是占位符,它会帮你占好位置,等你需要的时候直接将html传入,它会帮你显示出来. 也有人说:props可以将数据从父组件传入子组件,slot可以将html从父组件传入子组件.那么如何实现呢?

  • Vue匿名插槽与作用域插槽的合并和覆盖行为

    Vue 测试版本:Vue.js v2.5.13 Vue 文档: <slot> 元素可以用一个特殊的特性 name 来进一步配置如何分发内容.多个插槽可以有不同的名字.具名插槽将匹配内容片段中有对应 slot 特性的元素. 仍然可以有一个匿名插槽,它是默认插槽,作为找不到匹配的内容片段的备用插槽. 具体应用的时候: 1.匿名插槽的合并行为: <div id="app"> <myele> <div> default slot </div

  • 详解Vue 匿名、具名和作用域插槽的使用方法

    Vue 中的插槽在开发组件的过程中其实是非常重要并且好用的.Vue 的插槽也没有说很难使用,这篇文章简明扼要的介绍了三种插槽的用法. 匿名插槽 子组件定义 slot 插槽,但并未具名,因此也可以说是默认插槽.只要在父元素中插入的内容,默认加入到这个插槽中去.

  • 详解vue slot插槽的使用方法

    官方文档其实已经讲得很详细,我根据文档,把官方的小案例实现了一下,这样更直观 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="https://unpkg.com/vue@2.3.3/dist/vue.js"><

  • 从组件封装看Vue的作用域插槽的实现

    作用域插槽不是那么直观的一个概念.Vue文档使用了一段描述性的话来解释作用域插槽: 有的时候你希望提供的组件带有一个可从子组件获取数据的可复用的插槽 -- 但是在我们应用的某些部分,我们希望每个独立的待办项渲染出和 todo.text 不太一样的东西.这也是作用域插槽的用武之地. 但在我看来,至少是第一次读到的时候,这段话相当不好理解.插槽不是分发内容到子组件吗,为什么还要从子组件中获取数据?不是已经有了通过emit事件的方法从子组件向父组件传递数据吗,为什么需要它?作用域插槽到底是来干嘛的?-

  • vue学习笔记之作用域插槽实例分析

    本文实例讲述了vue学习笔记之作用域插槽.分享给大家供大家参考,具体如下: <child></child> Vue.component('child', { data: function () { return { list: [1, 2, 3] } }, template: '<div> <ul> <li v-for="item of list">{{item}}</li> </ul> </di

  • Vue中slot插槽作用与原理详解

    目录 1.作用 2.插槽内心 2.1.默认插槽 2.2.具名插槽(命名插槽) 2.3.作用域插槽 实现原理 1.作用 父组件向子组件传递内容 扩展.复用.定制组件 2.插槽内心 2.1.默认插槽 把父组件中的数组,显示在子组件中,子组件通过一个slot插槽标签显示父组件中的数据. 子组件 <template> <div class="slotChild"> <h4>{{msg}}</h4> <slot>这是子组件插槽默认的值&

  • 关于VUE的编译作用域及slot作用域插槽问题

    什么是插槽?插槽的指令为v-slot,它目前取代了slot和slot-scope,插槽内容,vue实例一套内容分发的api,将slot元素作为承载分发内容的出口. 插槽分为单个插槽,具名插槽,还有作用域插槽,前两种比较简单这里就不赘述了,今天的重点是讨论作用域插槽. 简单来说,前两种插槽的内容和样式皆由父组件决定,也就是说显示什么内容和怎样显示都由父组件决定: 作用域插槽的样式由父组件决定,内容却由子组件控制.简单来说:前两种插槽不能绑定数据,作用域插槽是一个带绑定数据的插槽. 下面给大家介绍V

  • Vue具名插槽+作用域插槽的混合使用方法

    vue + elementui 的项目中,通过后端返回的数据动态封装表单组件. 其中有些场景: 1.有些下拉框是联动的,例如前面的一个下拉框选择值之后,后一个下拉框才根据前面的下拉框选择的值加载数据: 2.有些输入框后面跟一个图形操作等等 上面的需求就需要用到插槽了. 这里只简单的介绍 具名插槽+作用域插槽 混合在一起使用的方法. 其中组件 mulForms.vue 里面封装的代码是(注意 slot里面的写法): <template v-if="item.slotName">

  • 使用Vue的slot插槽分发父组件内容实现高度复用、更加灵活的组件(推荐)

    写在前面 之前写过一篇关于vue实现dialog会话框组件的文章http://www.jb51.net/article/139218.htm 讲到了如何实现一个vue对话框组件,其中涉及到了父组件和子组件的通信,这个不用多说,看我之前的文章就能明白,文章最后也说到了,我们可以使用slot插槽来编写组件,slot用来分发内容到子组件中,从而实现组件的高度复用,编写的组件更加灵活. 还是结合对话框的例子,使用slot来实现对话框组件 注册一个名叫dialog-tip的全局组件 Vue.compone

随机推荐