vue-ganttastic甘特图label标签横向滚动固定方法

这个甘特图之前插件里,没有找到能固定label标签在屏幕上的办法,用css各种办法都没有实现,所以我我直接手写定位,用js监听滚动条滚动的距离,然后同步移动甘特图label标签,造成一种定位的错觉,以下是代码:

我用的是介绍 | Pure Admin 保姆级文档(已更新至最新版v6.0.0)这个前端框架,感觉功能还是非常完善的,作者全职做开源,希望大家也多多支持。

这个是全部甘特图的示例代码

TypeScript 复制代码
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from "vue";
// https://zunnzunn.github.io/vue-ganttastic/introduction.html
import { GGanttChart, GGanttRow } from "@infectoone/vue-ganttastic";

// 添加滚动位置状态
const scrollLeft = ref(0);
// 添加容器引用
const containerRef = ref(null);

// 现有数据保持不变
const context = ref([
  [
    {
      week: "星期一",
      beginDate: "06:00",
      endDate: "22:00",
      label_column_title: "123",
      ganttBarConfig: {
        id: "0",
        hasHandles: true,
        label: "需求收集和分析  负责人:小张",
        style: {
          background: "#e96560"
        }
      }
    }
  ],
  [
    {
      week: "星期二",
      beginDate: "09:00",
      endDate: "18:00",
      ganttBarConfig: {
        id: "1",
        hasHandles: true,
        label: "系统设计  负责人:小强",
        style: {
          background: "#5ccfa3"
        }
      }
    }
  ],
  [
    {
      week: "星期三",
      beginDate: "07:00",
      endDate: "20:00",
      ganttBarConfig: {
        id: "2",
        hasHandles: true,
        label: "编码实现  负责人:老李",
        style: {
          background: "#77d6fa"
        }
      }
    }
  ],
  [
    {
      week: "星期四",
      beginDate: "06:00",
      endDate: "21:00",
      ganttBarConfig: {
        id: "3",
        hasHandles: true,
        label: "编码实现  负责人:小明",
        style: {
          color: "#fff",
          background: "#1b2a47"
        }
      }
    }
  ],
  [
    {
      week: "星期五",
      beginDate: "05:00",
      endDate: "19:00",
      ganttBarConfig: {
        id: "4",
        hasHandles: true,
        label: "内部测试  负责人:小雪",
        style: {
          background: "#5ccfa3"
        }
      }
    }
  ],
  [
    {
      week: "星期六",
      beginDate: "10:00",
      endDate: "22:00",
      ganttBarConfig: {
        id: "5",
        hasHandles: true,
        label: "系统优化和文档整理  负责人:小欣",
        style: {
          background: "#f8bc45"
        }
      }
    }
  ],
  [
    {
      week: "星期天",
      beginDate: "04:00",
      endDate: "23:59",
      ganttBarConfig: {
        id: "6",
        immobile: false,
        hasHandles: false,
        label: "部署和上线  负责人:老王",
        style: {
          background: "#f3953d"
        }
      }
    }
  ],
  [
    {
      week: "星期天",
      beginDate: "04:00",
      endDate: "23:59",
      ganttBarConfig: {
        id: "6",
        immobile: false,
        hasHandles: false,
        label: "部署和上线  负责人:老王",
        style: {
          background: "#f3953d"
        }
      }
    }
  ]
]);

// 滚动事件处理函数
function handleScroll(e) {
  scrollLeft.value = e.target.scrollLeft;
  console.log("滚动事件触发", scrollLeft.value);
  const labels = document.querySelectorAll(
    ".g-gantt-row-label, .g-gantt-row-label-container"
  );
  labels.forEach(label => {
    label.style.position = "absolute";
    label.style.left = scrollLeft.value + "px";
  });
}

// 添加和移除滚动事件监听
onMounted(() => {
  // 延迟添加事件监听,确保DOM已完全渲染
  setTimeout(() => {
    if (containerRef.value) {
      containerRef.value.addEventListener("scroll", handleScroll);
      console.log("滚动监听已添加", containerRef.value);
    }
  }, 500);
});

onUnmounted(() => {
  if (containerRef.value) {
    containerRef.value.removeEventListener("scroll", handleScroll);
    console.log("滚动监听已移除");
  }
});

function getWeekRange() {
  const today = new Date();
  const dayOfWeek = today.getDay();

  const startDate = new Date(today);
  startDate.setDate(today.getDate() - dayOfWeek + 1);

  const endDate = new Date(startDate);
  endDate.setDate(startDate.getDate() + 6);

  const formatDate = date => {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");
    return `${year}-${month}-${day}`;
  };

  const currentWeekStart = formatDate(startDate);
  const currentWeekEnd = formatDate(endDate);

  return {
    currentWeekStart,
    currentWeekEnd
  };
}

const weekRangeInChina = getWeekRange();
</script>

<template>
  <div ref="containerRef" class="gantt-container">
    <g-gantt-chart
      chart-start="00:00"
      chart-end="23:59"
      precision="hour"
      date-format="HH:mm"
      bar-start="beginDate"
      bar-end="endDate"
      grid
      class="full-width-gantt"
    >
      <template #upper-timeunit>
        <h1>
          {{
            `${weekRangeInChina.currentWeekStart} / ${weekRangeInChina.currentWeekEnd}`
          }}
        </h1>
      </template>
      <g-gantt-row
        v-for="(item, index) in context"
        :key="index"
        :bars="item"
        :label="item[0].week"
        highlight-on-hover
      />
    </g-gantt-chart>
  </div>
</template>

<style>
/* 全局样式,确保能覆盖组件内部样式 */
.g-gantt-row-label,
.g-gantt-row-label-container {
  position: relative !important;
  transition: none !important;
}

.gantt-container {
  width: 100%;
  overflow-x: auto;
  padding-bottom: 10px;
}

.full-width-gantt {
  min-width: 1500px;
  width: 200%;
}

/* 修改标签宽度样式 */
.g-gantt-row-label {
  width: 100px !important;
  min-width: 100px !important;
  max-width: 100px !important;
  box-sizing: border-box !important;
  overflow: hidden !important;
  text-overflow: ellipsis !important;
}
</style>

重点处理方法是:

TypeScript 复制代码
// 添加滚动位置状态
const scrollLeft = ref(0);
// 添加容器引用
const containerRef = ref(null);

// 添加和移除滚动事件监听
onMounted(() => {
  // 延迟添加事件监听,确保DOM已完全渲染
  setTimeout(() => {
    if (containerRef.value) {
      containerRef.value.addEventListener("scroll", handleScroll);
      console.log("滚动监听已添加", containerRef.value);
    }
  }, 500);
});


// 滚动事件处理函数
function handleScroll(e) {
  scrollLeft.value = e.target.scrollLeft;
  console.log("滚动事件触发", scrollLeft.value);
  const labels = document.querySelectorAll(
    ".g-gantt-row-label, .g-gantt-row-label-container"
  );
  labels.forEach(label => {
    label.style.position = "absolute";
    label.style.left = scrollLeft.value + "px";
  });
}
onUnmounted(() => {
  if (containerRef.value) {
    containerRef.value.removeEventListener("scroll", handleScroll);
    console.log("滚动监听已移除");
  }
});
相关推荐
远离UE48 小时前
UE5 Substrate Thin Film 源码拆析
开发语言·javascript·ue5
keyipatience8 小时前
JavaScript学习(1)书写位置,变量、数据类型、运算符
开发语言·前端·javascript·css·学习
鶴哥只手遮天11 小时前
Vue 3 核心源码深度剖析系列(v3.5.44)-第 1 章 项目全景:monorepo 架构与工程化体系
前端·vue.js·开源
SensorFlow12 小时前
曝光埋点别放在组件渲染里:连续可见与去重范围怎么验收
javascript
harris148154352975812 小时前
能解码不等于能信任:JWT 的签名到底验的是什么
javascript
liqingdi43712 小时前
[SWPUCTF 2023 秋季新生赛]Easy SMC
服务器·前端·javascript
日耗10亿Token被老板赶出门12 小时前
REA 火了:一个 Electron 按钮的调用链,它能追到哪一步?
javascript·electron
OpenTiny社区13 小时前
多会话 + 流式输出怎么落地?TinyRobot Kit 对话数据层深度解析
前端·vue.js
青柠之夏cc13 小时前
Laravel服务容器底层原理揭秘
javascript·rpc·laravel
变与不变80614 小时前
防抖节流详解
开发语言·前端·javascript