项目中开发固定表头和首列的表格【付代码】

news2025/1/12 20:47:01

前言
前段时间做移动端的项目,项目中需要一个固定表头和首列的表格,但由于是移动端的,组件库里没有类似的,于是,就去网上找看有没有类似的,结果越找越气,10个文章9个抄,抄也行,你倒是抄个能用的啊,一篇根本就不能用的文章,抄个什么劲?有意义???
没办法,只有自己写一个了。

在这里插入图片描述

实现思路
1、首先分为四部分,左上角固定不动的表头,表头部分,首列部分,表格主体部分
2、整个表格添加定位position: relative;左上角表头添加position: fixed;
3、给白色主体部分添加滚动监听事件,在滑动的同时,使首列的scrollLeft等于主体部分的scrollLeft值;使表头的scrollTop值等于主体的scrollTop值;

2021-06-03 最近又对这个表格优化了下,以上操作是第一版,本版本优化了向左滚动同时也可以向上滚动的问题,体验不好;要求是向左右滚动则不允许上下滚动,向上下滚动不允许左右滚动;
思路是如下:
1、通过touchstart记录初始的鼠标点击位置;
2、通过touchmove记录移动时鼠标位置;
3、通过位置的x轴和y轴的差值判断用户手指移动位置;
4、左右滑动时,把盒子的overflowY设为hidden;上下滑动时,把盒子得overflowX设为hidden;

<template>
  <div class="pages">
    <div class="tables">
      <div class="tits">
        <div class="titsLeft">
          <p>左上角</p>
        </div>
        <div class="titsRight" ref="titsRight">
          <div>
            <p v-for="(item, i) in 50" :key="i">表头{{ i + 1 }}</p>
          </div>
        </div>
      </div>

      <div class="tbody" @scroll="scrollEvent($event)" ref="tbodyRight" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend">
        <div class="tbodyLeft" ref="tbodyLeft">
          <div ref="tbodyLeftItem">
            <p v-for="(item, i) in 50" :key="i">首列{{ i + 1 }}</p>
          </div>
        </div>
        <div class="tbodyRight">

          <div v-for="(item, i) in 50" :key="i" class="row">
            <p v-for="(item1, i1) in 50" :key="i1">{{ i + 1 }}-{{ i1 + 1 }}</p>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "tables",
  data() {
    return {
      /* 移动所需参数 */
      startX: 0,
      startY: 0,
      endX: 0,
      endY: 0,
      isMove: false,
    };
  },
  methods: {
    scrollEvent(e) {
      this.$refs.titsRight.style.left = -e.target.scrollLeft + 60 + "px";
      this.$refs.tbodyLeftItem.style.top = -e.target.scrollTop + "px";
    },

    /* 监听滑动开始 */
    touchstart(e) {
      /* 阻止一些默认事件 */
      // e.preventDefault();
      /* 记录初始位置 */
      this.startX = e.touches[0].pageX;
      this.startY = e.touches[0].pageY;
      console.log(this.startX, this.startY);
    },
    /* 监听滑动移动 */
    touchmove(e) {
      /* 判断是否滚动 */
      this.isMove = true;
      /* 监听滑动最终结束的位置 */
      this.endX = e.touches[0].pageX;
      this.endY = e.touches[0].pageY;

      /* 判断移动方向 */
      let X = this.endX - this.startX,
        Y = this.endY - this.startY;
      /* 判断是否移动还是点击 */
      if (this.isMove) {
        if (X > 0 && Math.abs(X) > Math.abs(Y)) {
          //向右
          console.log("向右");
          this.$refs.tbodyRight.style["overflowY"] = "hidden";
          this.$refs.tbodyRight.style["overflowX"] = "auto";
        } else if (X < 0 && Math.abs(X) > Math.abs(Y)) {
          //向左
          console.log("向左");
          this.$refs.tbodyRight.style["overflowY"] = "hidden";
          this.$refs.tbodyRight.style["overflowX"] = "auto";
        } else if (Y > 0 && Math.abs(Y) > Math.abs(X)) {
          //向下
          console.log("向下");
          this.$refs.tbodyRight.style["overflowX"] = "hidden";
          this.$refs.tbodyRight.style["overflowY"] = "auto";
        } else if (Y < 0 && Math.abs(Y) > Math.abs(X)) {
          //向上
          console.log("向上");
          this.$refs.tbodyRight.style["overflowX"] = "hidden";
          this.$refs.tbodyRight.style["overflowY"] = "auto";
        } else {
          //没有
          // console.log("没有");
        }
      } else {
        // console.log("没有");
      }
    },
  },
};
</script>
<style scoped lang="scss">
::-webkit-scrollbar {
  /*隐藏滚轮*/
  display: none;
}
* {
  margin: 0;
  padding: 0;
}
p {
  width: 60px;
  height: 40px;
  text-align: center;
  line-height: 40px;
  flex-shrink: 0;
}
.tables {
  width: 100%; //自定义表格整体宽度
  font-size: 12px;
  overflow: hidden;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  position: relative;
  // border-right: 1px solid red;
  // border-bottom: 1px solid red;
  // border-bottom: 1px solid #ccc;
  .tbody {
    height: 400px; //自定义表格内容高度
    overflow: auto;
  }
  > div {
    display: flex;
  }
  div {
    flex-shrink: 0;
  }
  .tits {
    height: 40px;
    padding-left: 60px;
    background-color: #fff;
  }
  .titsLeft,
  .tbodyLeft {
    width: 60px;
  }
  .titsRight,
  .tbodyRight {
    width: 250px; //自定义表头表体内容宽度
  }
  .titsLeft {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 100;
    p {
      width: 60px;
      background-color: #fff;
      border-bottom: 1px solid #ccc;
    }
  }
  .titsRight {
    height: 40px;
    position: absolute;
    top: 0;
    div {
      display: flex;
      right: 17px;
      p {
        background-color: #fff;
        border-bottom: 1px solid #ccc;
      }
    }
  }
  .tbodyLeft {
    // overflow: hidden;
    white-space: nowrap;
    height: 100%;
    background-color: #fff;
    div {
      margin-top: 40px;

      width: 60px;
      background-color: #fff;
      left: 0;
      top: 0px;
      position: absolute;
      overflow: hidden;
      p {
        border-bottom: 1px solid #ccc;
      }
      // padding-top: 40px;
      // bottom: 17px; //避开下方滚动条位置
    }
  }
  .tbodyRight {
    white-space: nowrap;
    background-color: none;
    display: flex;
    flex-direction: column;
    .row {
      display: flex;
      p {
        border-bottom: 1px solid #ccc;
      }
    }
  }
}
</style>

总结

以上就是今日分享的全部内容。希望能对大家的学习有所帮助,小伙伴们评论区留下“管用",记得三联哦。 还有更多知识分享,欢迎拜访链接: 首页

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

安全狗入选网络安全行业全景图(第十版)多个细分领域

4月7日&#xff0c;安全牛正式发布第十版网络安全行业全景图。 作为国内云原生安全领导厂商&#xff0c;安全狗也凭借综合的安全能力脱颖而出入选全景图多个领域。 据悉&#xff0c;全景图报告调研基于企业自主申报&#xff0c;并对申报企业收录有严格要求&#xff0c;安全牛…

Zookeeper集群+Kafka集群

目录 一、Zookeeper Zookeeper 概述 定义 工作机制 Zookeeper特点 Zookeeper数据结构 ZooKeeper应用场景 统一命名服务 统一配置管理 统一集群管理 服务器动态上下线 软负载均衡 第一次启动选举机制 非第一次启动选举机制 二、部署Zookeeper集群 1、实验准备 2…

第60章 用户增、修、删的前端实现

1 \src\components\Users\AddUser.vue <template> <!-- elmentUI 子页面的渲染显示注意事项说明&#xff1a; 子页面的渲染显示必须的使用“<el-dialog></el-dialog>标签及其所包含的子标签&#xff0c;否则子页面将不会被渲染显示出来。” --> <…

Python学习笔记--判断语句

&#xff08;一&#xff09; 布尔类型和比较运算符 1. 布尔类型&#xff1a;判断结果 True&#xff1a;表示真&#xff08;是、肯定&#xff09; False&#xff1a;表示假&#xff08;否、否定&#xff09; """ 演示布尔类型的定义 以及比较运算符的应用 "…

BCM系统组成及控制原理

1 输入控制 由于负载能力、抗干扰能力等客观情况。许多信号量无法直接施加至MCU之上&#xff0c;须有适当的输入电路(Input circuit)将信号进行隔离、调理&#xff0c;方可安全可靠地传递给MCU。 下面以开关信号和脉冲信号2种来分述。 1)开关信号的输入。 即将系统与电源正…

高频算法:Leetcode53 最大子数组和

今天讲的是Leetcode第53题&#xff0c;最大子数组和 首先观察题目&#xff0c;题目需要我们找出具有最大和的连续子数组&#xff0c;直接拿题目中的示例来做一个演示&#xff0c;找一找什么规律下的连续子数组才能得到最大的和 先从-2开始&#xff0c;-2 1 -1 此时我们的和…

【Python】Python读写.xlsx文件(基本操作、空值补全等)

【Python】Python读写.xlsx文件&#xff08;Pandas&#xff09; 文章目录【Python】Python读写.xlsx文件&#xff08;Pandas&#xff09;1. 介绍2. Pandas读写xlsx文件2.1 基本操作2.1.1 实现任务2.1.2 代码2.1.3 结果2.2 进阶操作2.2.1 写操作2.2.2 查看数据表的基本信息2.2.2…

集中一个主题,密集学习几个月,突飞猛进

集中一个主题&#xff0c;密集学习几个月大长进 诺贝尔奖获得者西蒙发现 密集学习了几个月品牌营销的知识 长进明显 原来是有科学规律的 趣讲大白话&#xff1a;大力出奇迹 【趣讲信息科技132期】 **************************** 西蒙学习法&#xff1a;“对于一个有一定基础的人…

KANO模型-产品需求调研利器

最近要做一个项目&#xff0c;需要调研客户的真实需求&#xff0c;我们有一些可提供的功能&#xff0c;需要通过问卷调研出客户对功能的优先级需求。但问卷调研的结果能反映客户的真实需求和痛点吗&#xff1f;如何给这些需求排优先级&#xff0c;以及所占的权重&#xff1f;如…

【python】只需一段代码,剪辑一个视频——Moviepy详解

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言一、准备二、视频剪辑三、视频拼接四、逐帧变化四、导出GIF总结前言 知道吗&#xff0c;用moviepy一行代码就能够快速剪辑视频中某个区间的片段&#xff1a; cl…

mac m1系统安装安卓手机模拟器

背景&#xff1a;本人是一名开发人员&#xff0c;本地小程序上的需要地图导航到手机上&#xff0c;所以找到一个mac&#xff08;m1&#xff09;安装安卓模拟器的方案&#xff0c;这里记录分享一下。 废话不多说直接上步骤&#xff0c;很详细跟着步骤走就能完成&#xff01;&am…

【MySQL】delete和truncate的用法和区别

一、delete和truncate的用法 有如下数据表t_student 关键字delete和truncate都用来清除表中数据&#xff0c;语法结构为&#xff1a; delete from t_student;truncate table t_student; 两条SQL操作后的结果一样&#xff1a;删除了表中数据&#xff0c;但是会保留表的结构&a…

OpenAI Embedding:快速实现聊天机器人(一)

theme: orange 本文正在参加「金石计划」 上文 OpenAI Embedding&#xff1a;基于人工智能的搜索新篇章 有讲到Embedding的基础概念以及OpenAI Embedding 的能力和应用场景&#xff0c;这篇文章讲讲如何手把手构建聊天机器人。 聊天机器人介绍 聊天机器人作为一项重要的企业级服…

Qt 数据库SQL

Qt 数据库SQL用户接口层SQL接口层驱动层创建连接数据库查询两个数据库示例用户接口层、SQL接口层和驱动层是数据库系统中的三个重要组成部分&#xff0c;它们分别负责不同的功能。 用户接口层 用户接口层 用户接口层是用户与数据库系统交互的界面。它提供了一些简单易用的工具…

HDSF 简介

目录 一、HDFS 的设计特点是 二、什么零拷贝 2.1 传统情况&#xff1a; 2.2 零拷贝技术&#xff1a; 三、什么是DMA 四、HDFS 的关键元素 五、HDFS 运行原理 六、HDFS 数据合并原理 七、HDFS 写的原理 八、HDFS 读的原理 九、分块存储 十、 安全模式 十一、 MapRedu…

如何使用微服务架构?使用过程需要注意什么?

一、使用微服务架构的规范 1.1 服务拆分 微服务的服务拆分是根据业务领域和业务功能来划分的&#xff0c;目的是将复杂的单体应用程序分解为小型、自治的服务&#xff0c;每个服务都专注于处理一个特定的业务领域或功能。 以下是微服务拆分的一些常见策略&#xff1a; 领域…

JavaEE——volatile、wait、notify三个关键字的解释

文章目录一、volatile和内存可见性1.解释内存可见性问题2. volatile 的使用与相关问题二、wait 和 notify1.wait 方法2.notify() 方法3. 关于 notifyAll() 方法4. wait 和 sleep 之间的简单比较一、volatile和内存可见性 前面的文章&#xff0c;我们已经提及到了内存可见性问题…

硬件设计--stm32自动下载电路设计

1 参考博客&#xff1a; 1、Stm32 一键下载电路详解 2、启动模式&#xff0c;BOOT0和BOOT1详解 3、STM32自动ISP电路设计 4、STM32 USB接口 一键下载电路详解与过程分析 2 下载软件分享&#xff1a; 参考博客&#xff1a;FlyMcu - 用于STM32芯片ISP串口程序一键下载的免费软…

【速记】Postgresql中几个ResourceOwner的含义

几个ResourceOwner的含义 总结下几个resowner的含义&#xff1a; 事务结构内的resowner&#xff1a;TransactionState→curTransactionOwner 含义&#xff1a;跟随事务结构体创建&#xff0c;会申请内存&#xff0c;跟随事务结构释放。每层事务都有自己的curTransactionOwner…

Vivado 下按键实验

Vivado下按键实验 实验原理 PL通过按键的开关状态控制led的亮灭&#xff0c;按键按下的时候灯亮&#xff0c;按键未按下的时候灯灭。 这里的描述有些问题&#xff0c;PL_LED1为高的时候&#xff0c;LED两端的电压都为高&#xff0c;灯应该是不亮的&#xff0c;所以按照下面实…