antd table列选中效果实现

前言

开发中有一个需要呈现不同时间点各个气象要素的值需求,我觉得一个table可以实现这类数据的展示,只是因为时间点时关注的重点,所以需要列选中效果,清晰的展示时间点下的要素数据。我选择的是antd的table组件,这个组件没有列选中的效果,所以还是需要自己动手丰衣足食,改造一下。

分析

这个功能的难点在于列选中效果,我们需要给他一个背景加上边框,虽然antd的table没有列选中效果,但是它提供了customCell,customHeaderCell,我们可以根据这些回调函数的特点灵活使用实现列选中效果。

参数说明类型用途
customCell设置单元格属性Function(record, rowIndex)根据activeColIndex参数,为选中列包含的单元格添加class,并且为最后一个单元格加上“lastCol”的class,因为最后一个需要加上下边框
customHeaderCell设置头部单元格属性Function(column)主要为选中列的第一个单元格加上class,因为表头单元格需要加上上边框

源代码

/**
* CustomTable.vue
* @Author ZhangJun
* @Date  2024/5/28 11:39
**/
<template>
  <a-spin :spinning="loading">
    <template v-if="dataSource&&dataSource.length>0">
      <a-table :pagination="false"
               :columns="getColumns"
               :dataSource="dataSource"
               rowKey="itemCode"
               :scroll="{y:dataSource.length>9?'280px':false}"></a-table>
    </template>

    <custom-empty v-else
                  desc="暂无机场高影响数据"
                  sub-title="NO DATA IS AVAILABLE"
                  style="margin: 8% auto;"></custom-empty>
  </a-spin>
</template>

<script>
import CustomEmpty from "@/components/CustomEmpty.vue";
import moment from "moment";
import {HighImpactWeatherApi} from "@/api/HighImpactWeatherApi";
import WizStyleHelper from "@/utils/leaflet/WizStyleHelper";
import BigNumber from "bignumber.js";

export default {
  name: "CustomTable",
  components: {CustomEmpty},
  props: {
    currentDateTime: {type: String},
    //选择的可显示的要素
    visibleItemsConfig: {type: Array, default: () => ([])},
    airportId: {type: String}
  },
  data() {
    return {
      loading: false,
      itemDefaultConfig: {
        visibility: {unit: 'm', name: '能见度'},
        wins: {unit: 'm/s', name: '风'},
        rain: {unit: 'mm', name: '雨'},
        lowTemperature: {unit: '℃', name: '低温'},
      },
      itemColors: {},//要素配色缓存
      dataSource: [],
      activeColIndex: -1,//现在选中的列
    }
  },
  computed: {
    /**
     * 动态获取表格的columns
     * @returns {*[]}
     */
    getColumns() {
      //获取各种要素的颜色
      let colors = this.visibleItemsConfig?.map(({styleCode}) => {
        return [styleCode, this.getItemColor(styleCode)];
      }) || [];
      this.itemColors = Object.fromEntries(colors);

      //要素名称列自定义
      let itemCodeCustomRender = (text) => {
        let {styleCode, pCode, name} = this.visibleItemsConfig?.find(({code}) => code === text);
        let unit = this.itemDefaultConfig?.[pCode]?.unit || '';
        let color = this.itemColors?.[styleCode];
        return <div class="flex justify-end" style="width:80px;">
          {name}
          <div style={{padding: '0 4px', color}}>{unit}</div>
        </div>
      };

      let dayDate = moment(this.currentDateTime, 'YYYYMMDDHHmmss');
      let columns_temp = [];
      for (let i = 0; i < 24; i++) {
        let dataIndex = dayDate.clone().add(i, 'hour');
        columns_temp = [...columns_temp, {
          align: 'center',
          title: dataIndex.format('HH:mm'),
          dataIndex: dataIndex.format('YYYYMMDDHH'),
          key: dataIndex.format('YYYYMMDDHH'),
          className: 'customCell',
          //为了实现列选中高亮效果
          customCell: (record, rowIndex) => {
            return {
              class: {
                activeCol: i === this.activeColIndex,//如果该cell所以选中的那一列中,就在上这个样式
                lastCol: rowIndex === this.dataSource.length - 1//如果该cell属于选中列的最后一个cell,就加上这个样式,因为要在这个cell加上下边框
              },
              on: {
                mouseenter: (e) => {
                  //赋值当前cell所在的列索引,为高亮列做准备
                  this.activeColIndex = i;
                },
                mouseleave: (event) => {
                  //清空
                  this.activeColIndex = -1;
                }
              }
            }
          },
          //头部需要加上上边框
          customHeaderCell: (column) => {//自定义表头
            return {
              class: {
                activeCol: i === this.activeColIndex,//该表头为选中列的表头,加上这个样式,因为列头需要加上边框
                headerCell: true
              },
            }
          },
          customRender: (text, record) => {
            text = Number(text);
            if (text >= 1000) {
              text = new BigNumber(text).toFixed(0);
            } else if (text < 1000 && text >= 100) {
              text = new BigNumber(text).toFixed(0);
            } else if (text < 100 && text >= 10) {
              text = new BigNumber(text).toFixed(1);
            } else if (text < 10 && text > 0) {
              text = new BigNumber(text).toFixed(2);
            }

            let {itemCode} = record;
            let {styleCode, legendImage, name, pCode} = this.visibleItemsConfig?.find(({code}) => code === itemCode);
            let unit = this.itemDefaultConfig?.[pCode]?.unit || '';
            //如果有图标就显示图标
            if (legendImage) {
              if (text > 0) {
                return <img height="15" title={`${name}${text} ${unit}`} src={legendImage} alt={name}/>;
              }
              return <div style={{
                padding: '4px 0',
                overflow: 'hidden',
                width: '28px',
                textAlign: 'center',
                cursor: 'default',
              }} title={`${name}${text} ${unit}`}>
                -
              </div>
            }

            let color = this.itemColors?.[styleCode];
            return <div style={{
              background: text > 0 ? color : '',
              padding: '4px 0',
              overflow: 'hidden',
              width: '28px',
              textAlign: 'center',
              cursor: 'default',
            }} title={`${name}${text} ${unit}`}>
              {text}
            </div>;
          }
        }];
      }

      return [{
        title: '',
        dataIndex: 'itemCode',
        key: 'itemCode',
        className: 'customCell',
        align: 'right',
        width: 80,
        customRender: itemCodeCustomRender,
      }, ...columns_temp];
    },
  },
  methods: {
    /**
     * 获取数据
     */
    fetchData() {
      if (this.currentDateTime && this.visibleItemsConfig?.length > 0 && this.airportId) {
        let startTime = moment(this.currentDateTime, 'YYYYMMDDHH').format('YYYYMMDDHH');
        let endTime = moment(this.currentDateTime, 'YYYYMMDDHH').add(23, 'hour').format('YYYYMMDDHH');
        let itemCodes = this.visibleItemsConfig?.map(({code}) => code).join(',');
        this.loading = true;
        HighImpactWeatherApi.getHighImpactSingleAirportFutureImpactInfo({
          startTime,// 2024051102,
          endTime,
          itemCodes,
          airportId: this.airportId
        }).then((res = {}) => {
          let {data} = res;
          if (data) {
            this.dataSource = itemCodes.split(',').map(itemCode => {
              return {itemCode, ...data[itemCode]};
            });
          }
        }, () => {
          this.dataSource = [];
        }).finally(() => {
          this.loading = false;
        });
      }
    },
    /**
     * 获取站点图例颜色
     * @param styleCode 配色code
     */
    getItemColor(styleCode) {
      if (styleCode) {
        const wizStyleHelper = new WizStyleHelper();
        const colorConfig = wizStyleHelper.getStyleImpl(styleCode);
        let {colors: [, color]} = colorHelper.getColorImpl(colorConfig.shaded.color).colorPalettes;
        return `rgba(${color.join(',')})`;
      }
      return undefined
    },
  },
  mounted() {
    this.fetchData();
    this.$watch(() => [this.currentDateTime, this.airportId, this.visibleItemsConfig], ([params1, params2, params3]) => {
      this.fetchData();
    });
  }
}
</script>

<style scoped lang="less">
/deep/ .customCell {
  background: transparent;
  padding: 4px 0 !important;
  border-color: transparent;
  border-width: 0 1px 0 1px;

  * {
    font-family: D-DIN, sans-serif;
    font-size: 12px;
    font-weight: normal;
    line-height: 12px;
    text-align: center;
    letter-spacing: 0;
    color: rgba(255, 255, 255, 0.6);
    white-space: nowrap;
  }
}


/deep/ .customRow {
  > td {
    font-family: D-DIN, sans-serif;
    font-size: 12px;
    font-weight: normal;
    line-height: normal;
    text-align: center;
    letter-spacing: 0;

    color: white;
  }
}

/deep/ .ant-table-header {
  background: transparent;

  &.ant-table-hide-scrollbar {
    margin-right: -0.69rem;
  }
}

/deep/ .ant-table-body {
  background: transparent !important;

  &::-webkit-scrollbar {
    /* 对应纵向滚动条的宽度 */
    width: 0.425rem;
    /* 对应横向滚动条的宽度 */
    height: 0.425rem;
  }

  &::-webkit-scrollbar-thumb {
    background: #198CF8;
    border-radius: 32px;
  }

  &::-webkit-scrollbar-track {
    background: rgba(7, 28, 65, 0.5);
    border-radius: 32px;
  }

  .ant-table-tbody {
    > tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected) > td {
      background: unset;
    }
  }
}

/deep/ .headerCell {
  border-width: 1px 1px 0;
  border-style: solid;
  border-color: transparent;
}

/deep/ .lastCol {
  border-width: 0 1px 1px;
  border-style: solid;
  border-color: transparent;
}

/deep/ .activeCol {
  background: rgba(77, 136, 255, 0.19) !important;
  //border-width: 0 1px 0 1px;
  border-style: solid;
  border-color: #5FACFF;

  &.headerCell {
    border-radius: 2px 2px 0 0;
  }

  &.lastCol {
    border-radius: 0 0 2px 2px;
  }
}
</style>

效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/662906.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python | Leetcode Python题解之第105题从前序与中序遍历序列构造二叉树

题目&#xff1a; 题解&#xff1a; class Solution:def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:if not preorder:return Noneroot TreeNode(preorder[0])stack [root]inorderIndex 0for i in range(1, len(preorder)):preorderVal pr…

JS实现彩色图片转换为黑白图片

1. 使用 Canvas 研究 canvas 时发现一个有趣的现象——将彩色图片巧妙地转换为黑白图片。以下是实现这一功能的简洁代码示例&#xff1a; <div style"display: flex"><img src"./panda.jpeg" /><button onclick"change()">转…

【AIGC】GPT-4o技术分析-浅谈

GPT-4o&#xff1a;人工智能技术的全新里程碑 一、引言二、GPT系列版本间的对比分析三、GPT-4o的技术能力分析多模态处理能力速度与性能优化情感理解与表达能力 四、个人整体感受五、结语 一、引言 在人工智能技术的浪潮中&#xff0c;OpenAI再次以其卓越的创新能力引领潮流。近…

电瓶车进电梯识别报警摄像机

随着电动车的普及&#xff0c;越来越多的人选择电动车作为出行工具。在诸多场景中&#xff0c;电梯作为一种常见的交通工具&#xff0c;也受到了电动车用户的青睐。然而&#xff0c;电动车进入电梯时存在一些安全隐患&#xff0c;为了提高电动车进电梯的安全性&#xff0c;可以…

【UE5.1 角色练习】08-物体抬升、抛出技能 - part2

目录 前言 效果 步骤 一、让物体缓慢的飞向手掌 二、向着鼠标方向发射物体 前言 在上一篇&#xff08;【UE5.1 角色练习】08-物体抬升、抛出技能 - part1&#xff09;的基础上继续完成角色将物体吸向手掌&#xff0c;然后通过鼠标点击的方向来发射物体的功能。 效果 步骤…

Nacos 进阶篇---Nacos服务下线做了哪些事情 ?(八)

一、引言 本章节是第一阶段最后一篇&#xff0c;那么我们今天要学习的源码内容是 “服务下线”. 当Nacos客户端下线的时候&#xff0c;是要去通知服务端&#xff0c;告诉服务端 “ 我已经下线&#xff0c;不可用了 ”。并且在服务下线时&#xff0c;还要去通知其他客户端服务更…

Linux 服务器配置 SSH 服务登录失败处理

任务目标 配置 Linux 服务器ssh远程登录失败处理机制&#xff0c;防止黑客爆破服务器密码 操作步骤 备份原配置文件 $ sudo cp /etc/pam.d/sshd /etc/pam.d/sshd.bak $ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak安装 pam_tally2 统计登陆失败次数 # 对于Debia…

UDP网络聊天室(更)

服务器端 #include <header.h> typedef struct node {char name[20];struct sockaddr_in cli_addr;struct node *next; }node,*node_p; typedef struct msg {char type;char name[20];char text[128]; }msg; node_p create_link() {node_p H(node_p)malloc(sizeof(node)…

嵌入式进阶——HID协议

&#x1f3ac; 秋野酱&#xff1a;《个人主页》 &#x1f525; 个人专栏:《Java专栏》《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 USB烧录USB HID协议USB协议组成通讯流程 官方USB HID范例文件说明修改PC端的显示 兼容库函数HID键盘USB调试工具USB 描述符设备描述…

29-ESP32-S3-WIFI篇-00 STA模式扫描全部 AP

ESP32-S3 WIFI_Driver 引言 ESP32-S3是一款集成了Wi-Fi和蓝牙功能的芯片。关于WIFI的部分&#xff0c;其实内容比我想象的要多得多。所以通常来说&#xff0c;如果你想要编写自己的Wi-Fi应用程序&#xff0c;最快捷的方法就是先找一个类似的示例应用&#xff0c;然后将它的相…

输入与输出的魔法:探索Python的内置函数

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、从键盘捕获输入&#xff1a;input()函数的力量 二、打印输出&#xff1a;print()函数的…

简单模拟实现shell(Linux)

目录​​​​​​​ 前言 展示效果 实现代码 前言 该代码模拟了shell的实现&#xff0c;也就是解析类似于“ls -a -l"的命令&#xff0c;当我们启动我们自己写的shell的可执行程序时&#xff0c;我们输入"ls"的命令&#xff0c;也可以展示出在shell中输入&…

50etf期权购是什么意思?

今天带你了解50etf期权购是什么意思&#xff1f;很多刚刚接触50ETF期权的投资者或许不太明白50ETF期权投资是一种什么样的投资&#xff0c;对于50ETF期权投资来说&#xff0c;有认购合约与认沽合约&#xff0c;那么“购”也就是认购的意思。 50etf期权购是什么意思&#xff1f;…

速看!!24上软考【电子商务设计师】真题回顾,含答案解析

2024上半年软考考试已经结束了&#xff0c;为大家整理了网友回忆版的电子商务设计师真题及答案&#xff0c;25-26日两批考试总共60道题。 上半年考试的宝子们可以对答案预估分数&#xff01;准备下半年考的宝子可以提前把握考试知识点和出题方向&#xff0c;说不定会遇到相同考…

当今世界三个最厉害的人物颜廷利:全球最受欢迎的点赞第一人

我们生活在一个历史的拐点&#xff0c;一个要求我们重新构思自我、解读世界以及预见未来的时代。在这个时代&#xff0c;那些能够洞悉社会发展的深层逻辑&#xff0c;并据此提出全新定义的人&#xff0c;将成为引领人类思维、塑造普遍价值观和主导全球发展议程的先锋。因此&…

插件“猫抓”使用方法 - 浏览器下载m3u8视频 - 合并 - 视频检测下载 - 网课下载神器

前言 浏览器下载m3u8视频 - 合并 - 网课下载神器 chrome插件-猫抓 https://chrome.zzzmh.cn/info/jfedfbgedapdagkghmgibemcoggfppbb 步骤&#xff1a; P.s. 推荐大佬的学习视频&#xff01; 《WEB前端大师课》超级棒&#xff01; https://ke.qq.com/course/5892689#term_id…

01_Spring Ioc DI案例,setter方法和构造方法注入(详解) + 思维导图

文章目录 一.概念实操Maven父子工程 二. IOC和DI入门案例【重点】1 IOC入门案例【重点】问题导入1.1 门案例思路分析1.2 实现步骤2.1 DI入门案例思路分析2.2 实现步骤2.3 实现代码2.4 图解演示 三、Bean的基础配置问题导入问题导入1 Bean是如何创建的【理解】2 实例化Bean的三种…

Java导出excel带图片(希望能帮助你们节省时间)

第一天太慌张&#xff0c;下班逃跑&#xff0c;一夜没睡好&#xff0c;第二天决定搞出来。 查了好多博客&#xff0c;感觉都挺繁琐的&#xff0c;好多工具类、引入类找不到。经过一上午的琢磨&#xff0c;终于搞定。记录一下 借鉴了这个博主的文章 需求前端点击导出按钮&#…

HackTheBox-Machines--Lazy

Lazy测试过程 1 信息收集 1.端口扫描 发现 SSH&#xff08;22&#xff09;、HTTP&#xff08;80&#xff09;端口 nmap -sC -sV 10.129.159.512.访问 80 端口 1.页面中存在注册功能&#xff0c;测试注册功能 页面返回登录页面及用户名 使用burpsuite观察注册请求 /register.p…

骑车不戴头盔监测摄像机

骑行是一种健康的出行方式&#xff0c;但是在骑行途中不戴头盔存在安全隐患&#xff0c;容易造成头部受伤。为了规范骑行行为&#xff0c;保障骑行安全&#xff0c;可以考虑使用骑车不戴头盔监测摄像机进行监测和识别。这种摄像机可以通过智能识别技术&#xff0c;实时监测骑自…