在 Vue 2中使用 dhtmlxGantt 7.1.13组件,并解决使用时遇到的问题汇总.“dhtmlx-gantt“: “^7.1.13“,

一、最终实现的结果gif展示

二、开发步骤简介

1、vue中引用甘特图包dhtmlx-gantt

// 可根据项目版本载入适配的版本
npm install dhtmlx-gantt@7.1.13

2、vue文件中引入

<script>
import { gantt } from 'dhtmlx-gantt/codebase/dhtmlxgantt.js'
import 'dhtmlx-gantt/codebase/dhtmlxgantt.css'
<script/>

3、html部分

<template>
 <div class="gantt-content"  style="width:100%;height: 100%;">
          <div ref="ganttContainer" style="width:100%;height: 100%;"></div>
    </div>
</template>

4、js部分

  mounted () {
    // 初始化甘特图  注意:保证先初始化,在加载数据,以防万一可以在此基础上自行修改为异步
    this.initGantt()
// 初始化数据
    this.loadData()
  },
  watch: {
    '$route.query.id': {
      handler (newId) {
        if (newId) {
          this.loadData('clearAll')
        }
      },
      immediate: true // 立即执行以处理初始加载
    }
  },
  methods: {
    async loadData (type) {
      this.spinning = true
      if (type === 'clearAll') { gantt.clearAll() } // 避免来回切换页面更改数据时甘特图数据展示混乱
      axiosxxx().then(res => {
        if (rres.code === 200) {
          // 处理任务阶段数据,甘特图回显
          let formattedGanttData = []
          formattedGanttData = res.data.progressItems.map(task => ({
            id: task.id,
            text: task.progressName, // 映射任务名称字段
            start_date: this.formatDate(task.startTime), // 转换为gantt标准字段
            parent: task.parentId,
            open: task.level === 1 ? true : undefined,
            level: task.level,
            duration: task.duration,
            status: task.status
          }))
          gantt.parse({ data: formattedGanttData })
          gantt.render() // 强制重绘
        } else {
          this.$message.error(res.msg)
        }
        this.spinning = false
      }).catch(err => {
        this.$message.error(err.msg)
        this.spinning = false
      })
    },
    // 处理时间格式
    formatDate (dateStr) {
      // 根据你的接口日期格式进行调整-gantt图时间格式要求固定
      let [year, month, day] = dateStr.split('-')
      return new Date(year, month - 1, day) // 月份减1,因为月份是从0开始的
    },
    initGantt () {
      // // 初始化容器
      gantt.init(this.$refs.ganttContainer)
      // 禁用所有交互
      gantt.config.editable = false
      gantt.config.drag_move = gantt.config.drag_resize = false
      gantt.config.select_task = false
      // 禁用编辑功能
      gantt.config.readonly = true
      gantt.config.drag_move = false
      gantt.config.drag_resize = false
      gantt.config.grid_editable = false
      // 隐藏操作栏配置
      gantt.config.tree_actions = true // 隐藏展开/折叠图标
      gantt.config.tree_line = false // 隐藏层级连线
      gantt.config.row_height = 30 // 调整行高适应多行内容
      // gantt.config.min_column_width = 120 // 防止列宽过小
      // 是否显示左侧树表格
      gantt.config.show_grid = true
      // 格式化日期-汉化
      gantt.locale.date = {
        month_full: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
        month_short: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
        day_full: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],
        day_short: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
      }
      gantt.locale.labels = {
        dhx_cal_today_button: '今天',
        day_tab: '日',
        week_tab: '周',
        month_tab: '月',
        new_event: '新建日程',
        icon_save: '保存',
        icon_cancel: '关闭',
        icon_details: '详细',
        icon_edit: '编辑',
        icon_delete: '删除',
        confirm_closing: '请确认是否撤销修改!', // Your changes will be lost, are your sure?
        confirm_deleting: '是否删除计划?',
        section_description: '描述:',
        section_time: '时间范围:',
        section_type: '类型:',
        section_text: '计划名称:',
        section_test: '测试:',
        section_projectClass: '项目类型:',
        taskProjectType_0: '项目任务',
        taskProjectType_1: '普通任务',
        section_head: '负责人:',
        section_priority: '优先级:',
        taskProgress: '任务状态',
        taskProgress_0: '未开始',
        taskProgress_1: '进行中',
        taskProgress_2: '已完成',
        taskProgress_3: '已延期',
        taskProgress_4: '搁置中',
        section_template: 'Details',
        /* grid columns */
        column_text: '计划名称',
        column_start_date: '开始时间',
        column_duration: '持续时间',
        column_add: '',
        column_priority: '难度',
        /* link confirmation */
        link: '关联',
        confirm_link_deleting: '将被删除',
        message_ok: '确定',
        message_cancel: '取消',
        link_start: ' (开始)',
        link_end: ' (结束)',
        type_task: '任务',
        type_project: '项目',
        type_milestone: '里程碑',
        minutes: '分钟',
        hours: '小时',
        days: '天',
        weeks: '周',
        months: '月',
        years: '年'
      }
      // 自定义左侧列配置
      gantt.config.columns = [
        { name: 'text',
          label: '任务名称',
          width: '*',
          tree: true,
          // 插入template,title解决字段显示不全的问题
          template: (task) => `
            <div title="${task.text}">
              ${task.text}
            </div>
          `
        },
        { name: 'start_date', label: '开始时间', align: 'center', width: 100 },
        { name: 'duration', label: '持续天数', align: 'center', width: 70 }
      ]
      // 任务条文本模板
      gantt.templates.task_text = (start, end, task) => {
        const cleanText = task.text
          .replace(/</g, '&lt;')
          .replace(/>/g, '&gt;')
          .replace(/"/g, '&quot;')
        return `
          <div class="gantt-task-title" title="${cleanText}">
            ${task.text}
          </div>
        `
      }
      // 自定义行样式(关键修改部分)
      gantt.templates.task_row_class = function (start, end, task) {
        if (task.level === 1) {
          return 'custom-gantt-level_1_row'
        }
        return ''
      }
      // 自定义任务条颜色模板(关键代码)
      gantt.templates.task_class = function (start, end, task) {
        // 调试输出(关键)
        // console.log(`[DEBUG] Task ${task.id}:`, {
        //   level: task.level,
        //   status: task.status,
        //   hasLevel: task.hasOwnProperty('level'),
        //   hasStatus: task.hasOwnProperty('status')
        // })
        switch (true) {
          case (task.level === 1):
            return 'custom-gantt-level_1_bar'
          case (task.level === 2 && task.status === 3):
            return 'custom-gantt-task_status_done'
          default:
            return ''
        }
      }
    }
  }

5、css部分

5-1、修改dhtmlxGantt 甘特图任务条的颜色

5-2、修改dhtmlxGantt 甘特图背景色

5-3、dhtmlxGantt 甘特图隐藏左侧侧边栏icon展示

<style>
.custom-gantt-level_1_row {
  background-color: #e6f3ff !important; /* 浅蓝色背景 */
}

/*修改任务条主题色*/
.gantt_task_line {
  background-color: #1890FF;
  border: 1px solid #1890FF;
}
.gantt_task_line.custom-gantt-level_1_bar {
  background: #FA8C16 !important;  /* 阶段任务条主色 */
  border-color: #FA8C16 !important;  /* 阶段边框颜色 */
}
.custom-gantt-task_status_done {
  background: #A3B1BF !important;  /* 已完成的任务条主色 */
  border-color: #A3B1BF !important;  /* 已完成的任务边框颜色 */
}

/* 隐藏文件夹图标 */
.gantt_tree_icon.gantt_folder_open,
.gantt_tree_icon.gantt_file,
.gantt_tree_icon.gantt_folder_closed {
  display: none !important;
}

/* 保留展开/收起图标 */
.gantt_grid_icon.gantt_open,
.gantt_tree_icon.gantt_close {
  display: inline-block !important;
  background-position: center; /* 修正图标位置 */
}
/* 调整层级缩进 */
.gantt_tree_indent {
  padding-left: 8px !important; /* 减少缩进间距 */
}
/*修改侧边栏hover颜色*/
.gantt_grid_data .gantt_row.odd:hover,
.gantt_grid_data .gantt_row:hover {
  background-color: #e6f3ff !important;
}
/* 在全局样式表中添加 */
.gantt_tree_text {
  display: inline-block;
  max-width: calc(100% - 24px); /* 为图标留出空间 */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: middle;
}

/*任务条显示不全时样式*/
.gantt_task_content {
  overflow: visible !important; /* 允许溢出显示 */
}
.gantt_task_title {
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none; /* 防止干扰拖拽操作 */
}

</style>

三、使用过程中问题总结

1、页面来回切换,数据更新后甘特图加载数据混乱的问题

使用gantt.clearAll()解决。但要注意再在初始化加载时不需要gantt.clearAll(),所以在再watch监听和初始化可以通过type却分

  watch: {
    '$route.query.id': {
      handler (newId) {
        if (newId) {
          this.loadData('clearAll')
        }
      },
      immediate: true // 立即执行以处理初始加载
    }
  },
  mounted () {
    this.initGantt()
    this.loadData() // 初始化不需要gantt.clearAll()
  },
methods: {
 async loadData (type) {
      ....
      if (type === 'clearAll') { gantt.clearAll() } // 避免来回切换页面更改数据时甘特图数据展示混乱
      // 源代码保持不变
.....
    },
}

2、自定义row背景色,根据状态不同自定义任务条的颜色

gantt.templates.task_class,gantt.templates.task_row_class

// 对应的class见css代码部分
initGantt(){

      // 自定义行样式(关键修改部分)
      gantt.templates.task_row_class = function (start, end, task) {
        if (task.level === 1) {
          return 'custom-gantt-level_1_row'
        }
        return ''
      }
      // 自定义任务条颜色模板(关键代码)
      gantt.templates.task_class = function (start, end, task) {
        // 调试输出(关键)
        // console.log(`[DEBUG] Task ${task.id}:`, {
        //   level: task.level,
        //   status: task.status,
        //   hasLevel: task.hasOwnProperty('level'),
        //   hasStatus: task.hasOwnProperty('status')
        // })
        switch (true) {
          case (task.level === 1):
            return 'custom-gantt-level_1_bar'
          case (task.level === 2 && task.status === 3):
            return 'custom-gantt-task_status_done'
          default:
            return ''
        }
      }

}

3、甘特图文案展示不全问题

甘特图禁止编辑操作后,左侧侧边栏text文案过长时展示不全,可自定义添加title

任务条持续时间短,文案展示不全时,添加title展示

      // 自定义左侧列配置
      gantt.config.columns = [
        { name: 'text',
          label: '任务名称',
          width: '*',
          tree: true,
          // 插入template,title解决字段显示不全的问题
          template: (task) => `
            <div title="${task.text}">
              ${task.text}
            </div>
          `
        },
        { name: 'start_date', label: '开始时间', align: 'center', width: 100 },
        { name: 'duration', label: '持续天数', align: 'center', width: 70 }
      ]

      // 任务条文本模板
      gantt.templates.task_text = (start, end, task) => {
        const cleanText = task.text
          .replace(/</g, '&lt;')
          .replace(/>/g, '&gt;')
          .replace(/"/g, '&quot;')
        return `
          <div class="gantt-task-title" title="${cleanText}">
            ${task.text}
          </div>
        `
      }

<think>好的,我需要帮助用户在Vue2项目中集成dhtmlx-gantt确保在多个页面渲染甘特图页面切换后能正常加载。首先,我要回顾一下用户提供的引用内容,看看有哪些有用的信息。 根据引用[1],安装dhtmlx-gantt是通过npm,然后在组件中引入使用。引用[3]和引用[5]提到需要在容器元素上使用ref,通过gantt.init初始化。引用[5]特别提到了异步数据加载的问题,建议使用v-if确保数据存在后再渲染组件,避免子组件加载数据还未准备好。 用户的问题是多页面渲染和页面切换后的正常加载。可能的问题点包括组件销毁未正确清理甘特图实例,或者路由切换DOM残留导致冲突。引用[4]和[2]提到配置项和分组功能,但当前问题更侧重于多页面渲染和生命周期管理。 首先,确保每个甘特图组件都有独立的容器ref,比如在每个页面的组件使用不同的ref名称,或者动态生成唯一的ref。不过,Vue中每个组件实例的ref是独立的,所以可能不需要特别处理,但要注意避免全局污染。 其次,在组件的生命周期钩子中正确初始化和销毁甘特图。当组件卸载,需要调用gantt.destroy()来清理实例,否则可能导致内存泄漏或残留事件监听器。引用中没有提到销毁步骤,但根据dhtmlx-gantt的文档,这是一个必要的步骤。 另外,路由切换,如果使用了keep-alive,可能需要处理activated和deactivated钩子来重新初始化或销毁实例。但用户没有提到使用keep-alive,所以暂先考虑常规的mounted和beforeDestroy钩子。 关于异步数据加载,引用[5]强调使用v-if等待数据加载完成后再渲染组件,避免空数据导致的初始化问题。因此,在每个页面的组件中,应确保数据获取后再初始化甘特图。 最后,可能存在样式冲突的问题,需要确保每个甘特图容器有足够的尺寸,比如设置width和height,如引用[3]中的样式设置。 总结步骤: 1. 在每个页面组件中独立引入和初始化甘特图2. 使用v-if控制组件渲染,确保数据就绪。 3. 在mounted钩子中初始化,beforeDestroy钩子中销毁实例。 4. 确保容器样式正确,避免布局问题。 5. 处理可能的全局配置冲突,比如语言设置。 可能存在遗漏的点是多个甘特图实例之间的相互影响,需要确认dhtmlx-gantt是否支持多实例,以及如何正确隔离配置。根据文档,每次调用gantt.init会绑定到指定的DOM元素,因此只要每个实例使用不同的容器,应该是可行的。 现在需要将这些步骤整理成结构化的回答,生成相关问题。</think>在Vue2项目中实现多页面dhtmlx-gantt甘特图渲染保证页面切换正常加载,需注意以下要点: ### 一、核心实现步骤 1. **组件封装** ```javascript // GanttComponent.vue export default { props: ['tasks'], mounted() { this.$nextTick(() => { gantt.init(this.$refs.ganttContainer) gantt.parse(this.tasks) }) }, beforeDestroy() { gantt.destroy() // 关键清理操作[^1][^5] } } ``` 2. **路由页面应用** ```javascript // PageA.vue <template> <gantt-component v-if="initialized" :tasks="ganttData" class="gantt-container" /> </template> <script> export default { data: () => ({ initialized: false, ganttData: [] }), async created() { this.ganttData = await fetchData() // 异步数据加载[^5] this.initialized = true } } </script> ``` ### 二、关键技术要点 1. **生命周期管理** - 必须通过`beforeDestroy`调用`gantt.destroy()`清理DOM事件和对象引用 - 使用`$nextTick`确保DOM渲染完成再初始化[^3] 2. **样式隔离方案** ```css /* 每个页面添加独立样式命名空间 */ .page-a .gantt-container { height: 80vh; border: 1px solid #e8e8e8; } ``` 3. **全局配置处理** ```javascript // 在入口文件初始化全局配置 import { gantt } from 'dhtmlx-gantt' gantt.config.xml_date = "%Y-%m-%d %H:%i" gantt.i18n.setLocale("cn") // 多语言配置[^2] ``` ### 三、常见问题解决方案 | 问题现象 | 解决方案 | |---------|---------| | 页面切换残留甘特图 | 检查是否遗漏destroy调用,添加路由守卫强制清理 | | 数据更新不渲染 | 使用`v-if`+`key`强制重建组件:`<component :key="routeKey">` | | 多实例事件冲突 | 为每个实例设置独立事件命名空间:`gantt.attachEvent('onTaskClick', handler, {scope: this})` |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值