作用域插槽

news/2024/7/10 23:05:08 标签: css, css3, es6, html5, vue

作用域插槽

一:假设第一个场景,需要你写一个商品卡片组件,并通过循环去展示多个卡片,并且要求能响应每个卡片上的图片或者其他内容的点击事件而跳转到商品详情页,你会怎么写?

我会使用如下的处理方式,首先将商品卡片写成一个组件Commodity.vue,而在CommodityList.vue中用一个v-for来处理商品卡片列表的展示。

<commodity v-for="(item,index) in commodities" @clickCommodity="onCommodityClick"></commodity>

Commodity组件通过$emit像父组件传递clickCommodity事件,并携带商品数据,父组件即可在onCommodityClick方法中得到数据,进行业务处理,这样便完成了一个基本的由子到父的数据传递。

二:如果再往上抽象一下呢?比如我有多个运营栏目,像淘宝首页有“有好货”,“爱逛街”这样两个栏目,每个栏目下都需要有一个商品卡片列表,那么商品卡片列表CommodityList.vue就要抽成组件了。而这个包含多个运营栏目的vue组件我假设它叫ColumnList.vue,在其中通过v-for调用了CommodityList组件。

业务来了,我希望把点击商品卡片的业务放在ColumnList.vue中处理。你们想象一下要怎么做?一种土办法就是商品按钮点击时,Commodity组件 e m i t 通 知 C o m m o d i t y L i s t . v u e , 而 C o m m o d i t y L i s t 接 着 把 事 件 用 emit通知CommodityList.vue,而CommodityList接着把事件用 emitCommodityList.vueCommodityListemit往上抛,那么ColumnList.vue就能处理这个点击事件了。这样做完全没有问题,但是显得子组件很不纯粹,跟业务都扯上关系了。

那么如何优雅地解决这个问题呢?这个时候,作用域插槽真正派上用场了。

通过作用域插槽将本应该由CommodityList处理的商品卡片点击业务onCommodityClick提升到ColumnList处理。

而CommodityList组件内部应该是改造成这样,slot接收来自父组件的商品卡片组件,这里面不涉及关于商品组件的业务,只关注其他业务和布局即可。最终就实现了组件和业务的剥离,这也是组件化的精髓所在吧。不知道有没有帮到您呢?

在这里插入图片描述
1.可以在第一层监听第三层组件的事件,并拿到第三层点击对象的数据
2.数据来源于第一层

第一层 List.vue(ColumnList.vue)

<template>
<el-row :gutter="20">
        <el-col :span="12" v-for="(column, index) in columnList" :key="index">
            <el-card class="box-card card-column">
                <div slot="header" class="clearfix">
                    <span>{{column.columnName}}</span>
                </div>
                <commodity-list :commodities="column.commodityList">
                    <template slot-scope="scope">
                    <!-- 这里只需要给Commodity组件传入数据,响应Commodity组件的clickCommodity事件即可。
                        事件不必携带参数,完全符合父到子的数据流向,而不会发生子组件又给父组件反向发数据的情况 -->
                        <commodity :modityData="scope.row" @clickcommodity="onCommodityClick(scope.row)"></commodity>
                    </template>
                </commodity-list>
            </el-card>
        </el-col>
</el-row>
</template>

<script>
import commodityList from './commodityList.vue'
import commodity from './commodity.vue'
export default {
  components: {
    commodityList,
    commodity
  },
  data() {
    return {
      columnList: [
        {
          columnName: '爱好货',
          commodityList: [
            {
              id: 1, commodityName: 'iphone1', detail: 'iphone1 iphone1'
            },
            {
              id: 2, commodityName: 'iphone2', detail: 'iphone2 iphone2'
            },
            {
              id: 3, commodityName: 'iphone3', detail: 'iphone3 iphone3'
            }
          ]
        },
        {
          columnName: '爱逛街',
          commodityList: [
            {
              id: 1, commodityName: 'iphone4', detail: 'iphone4 iphone4'
            },
            {
              id: 2, commodityName: 'iphone5', detail: 'iphone5 iphone5'
            },
            {
              id: 3, commodityName: 'iphone6', detail: 'iphone6 iphone6'
            }
          ]
        }
      ]
    }
  },
  methods: {
    onCommodityClick: function(i) {
      console.log(i)
    }
  }
}
</script>

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

第二层 commodityList.vue

<template>
  <el-row :gutter="20">
    <el-col :span="8" v-for="(item, index) in commodities" :key="index" style="margin-top:20px;">
      <!-- <span>{{item}}</span> -->
      <slot :row="item"></slot>
    </el-col>
  </el-row>
</template>

<script>
export default {
  props: {
    commodities: Array
  },
  data() {
    return {
    }
  }
}
</script>

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

第三层 commodity.vue

<template>
<div>
  <el-card class="box-card">
    <div slot="header" class="clearfix">
      <span>{{modityData.commodityName}}</span>
    </div>
    <div>
      <span @click="$emit('clickcommodity')">{{modityData.detail}}</span>
    </div>
  </el-card>
</div>

</template>

<script>
export default {
  props: {
    modityData: Object
  },
  data() {
    return {
    }
  }
}
</script>

<style lang="less" scoped>
.text {
    font-size: 14px;
  }

  .item {
    margin-bottom: 18px;
  }

  .clearfix:before,
  .clearfix:after {
    display: table;
    content: "";
  }
  .clearfix:after {
    clear: both
  }

  .box-card {
    width: 480px;
  }
</style>

vue卡片拖拽、自动排列交换位置、拖拽数据存取: https://www.cnblogs.com/xiaolucky/p/11699715.html.
vue封装一个卡片组件https://blog.csdn.net/qq_44775782/article/details/104157324.


http://www.niftyadmin.cn/n/1211904.html

相关文章

Jquery插件制作经验分享 之 json字符串转换插件(附:jQuery.Json.js)

前几天在做ecshop开发商城时&#xff0c;因其原使用的js框架和方法&#xff0c;与(我想使用的)Jquery框架有冲突&#xff0c;但(原js文件)其中的Ajax处理的json对象转换的方法又是不可缺少的方法&#xff0c;原来的不能用&#xff0c;只能自己想办法写或找了&#xff0c;为了省…

C#.NET 超大文件上传和断点续传的实现

文件夹数据库处理逻辑 public class DbFolder { JSONObject root; public DbFolder() { this.root new JSONObject(); this.root.put("f_id", ""); this.root.put("f_nameLoc", "根目录"); this.root.put("f_pid", "…

笔试中的编程题2

把 数字金额 转换成 中文金额。 如&#xff1a; 23424.12 ----> 贰万叁仟肆佰贰拾肆圆壹角贰分. 郁闷...转个过来&#xff08;教训&#xff09;。 importjava.math.BigDecimal;publicclassChineseCurrency { //中文金额单位数组String[] arrChineseUnit { "分"…

WebUploader 超大文件上传和断点续传的实现

需求&#xff1a; 支持大文件批量上传&#xff08;20G&#xff09;和下载&#xff0c;同时需要保证上传期间用户电脑不出现卡死等体验&#xff1b; 内网百兆网络上传速度为12MB/S 服务器内存占用低 支持文件夹上传&#xff0c;文件夹中的文件数量达到1万个以上&#xff0c;…

FLEX4 在Spark皮肤中定义与使用新的皮肤机制1

Flex 4 beta版Spark组件的一个主要优势来自于一种完全不同地皮肤机制&#xff0c;它为开发人员提供了对应用程序视觉上更强的控制。本教程将告诉你如何对可视化组件构建皮肤。任何使用这些皮肤的组件都内置了这种机制。为了说明这一点&#xff0c;我将通过PowerWindow来说明&am…

百度WebUploader超大文件上传和断点续传的实现

需求&#xff1a;项目要支持大文件上传功能&#xff0c;经过讨论&#xff0c;初步将文件上传大小控制在500M内&#xff0c;因此自己需要在项目中进行文件上传部分的调整和配置&#xff0c;自己将大小都以501M来进行限制。 第一步&#xff1a; 前端修改 由于项目使用的是BJUI前…

优化SQL Server数据库查询方法

本文详细介绍了优化SQL Server数据库查询方法。 SQL Server数据库查询速度慢的原因有很多&#xff0c;常见的有以下几种&#xff1a; 1、没有索引或者没有用到索引&#xff08;这是查询慢最常见的问题&#xff0c;是程序设计的缺陷&#xff09; 2、I/O吞吐量小&#xff0c;形成…

HTML超大文件上传和断点续传的实现

需求&#xff1a;项目要支持大文件上传功能&#xff0c;经过讨论&#xff0c;初步将文件上传大小控制在500M内&#xff0c;因此自己需要在项目中进行文件上传部分的调整和配置&#xff0c;自己将大小都以501M来进行限制。 第一步&#xff1a; 前端修改 由于项目使用的是BJUI前…