跳到主要内容

数据绑定与 Vue Gantt 的状态管理

本指南帮助你选择应用在哪些地方拥有 Gantt 数据,以及如何保持图表编辑的同步。请在每个页面上只选用一个所有权模型并保持一致。

Vue Gantt 支持两种常见模型:

  1. Vue state/store 作为真相源(大多数应用的最佳默认值)
  2. Gantt 作为真相源(面向图表密集页面的性能优化)

思维模型

包装器会将 props 同步到一个实时的 Gantt 实例中。若用户在图表中编辑数据,你需要决定:

  • 是通过包装器回调来更新 Vue 状态(Vue 自有模型),还是
  • 让图表/后端直接处理变更(Gantt 自有模型)

主要的陷阱在于所有权混合。如果 Vue 和 Gantt 实例都充当真相源,数据过时而被覆盖的情况很可能发生。

Vue State Or Store As Source Of Truth

在此模型中:

  • Vue 状态(或 Pinia)拥有 taskslinks
  • 包装器通过 props 接收数组
  • 图表编辑通过 data.savedata.batchSave 捕获
  • 回调处理程序更新状态
  • 更新后的状态会回流到包装器

此模型的类型建议:对响应式状态数组使用 SerializedTask[]SerializedLink[]

Best For

  • 需要 Vue UI 环绕且必须反映图表状态的页面
  • 已经使用 Pinia 或集中状态层的应用
  • 需要可预测的单向数据流的团队

Tradeoffs

  • 对于繁重操作,需要更多应用状态更新
  • 当在一个图表操作中发生多次编辑时,需要更多的同步工作

Avoid These Patterns

  • 通过 instance 修改 task/link 数据,同时继续从 Vue 状态传递过时的数组
  • 忽略包装器回调,期望图表编辑会自动保留在 Vue 状态中

Example: Store/Vue-Owned Flow

<script setup lang="ts">
import { ref } from "vue";
import VueGantt, {
type SerializedLink,
type SerializedTask,
type VueGanttDataConfig
} from "@dhtmlx/trial-vue-gantt";

const tasks = ref<SerializedTask[]>([]);
const links = ref<SerializedLink[]>([]);

const data: VueGanttDataConfig = {
save: (entity, action, item, id) => {
if (entity === "task") {
if (action === "create") tasks.value = [...tasks.value, item as SerializedTask];
if (action === "update") tasks.value = tasks.value.map(t => String(t.id) === String(id) ? item as SerializedTask : t);
if (action === "delete") tasks.value = tasks.value.filter(t => String(t.id) !== String(id));
}

if (entity === "link") {
if (action === "create") links.value = [...links.value, item as SerializedLink];
if (action === "update") links.value = links.value.map(l => String(l.id) === String(id) ? item as SerializedLink : l);
if (action === "delete") links.value = links.value.filter(l => String(l.id) !== String(id));
}
}
};
</script>

<template>
<VueGantt :tasks="tasks" :links="links" :data="data" />
</template>

对于多变更操作,请切换到 data.batchSave,并在分组批次中应用变更。

Gantt As Source Of Truth

在此模型中,图表和后端掌控大多数数据生命周期操作。Vue 较少进行实时镜像。

Best For

  • 非常大的数据集
  • 大量自动排程或批量更新流程
  • 以图表为焦点的页面,外部 UI 不需要对每一次实时变更立即生效

Tradeoffs

  • Vue state/store 中对实时图表状态的可见性较低
  • 如果偶尔将 prop 快照回推到包装器,需要更强的自律

Avoid These Patterns

  • 在没有对齐策略的情况下部分 Vue 镜像
  • 在用户编辑图表后重新喂入过时的服务器快照

Example: Gantt-Owned Transport

<script setup lang="ts">
import VueGantt from "@dhtmlx/trial-vue-gantt";

const data = {
load: "/api/gantt/load",
save: async (entity: string, action: string, payload: any, id: string | number) => {
const response = await fetch(`/api/gantt/${entity}`, {
method: action === "delete" ? "DELETE" : "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ action, payload, id })
});

// Create handlers should return the persistent ID when backend remaps it.
return await response.json();
}
};
</script>

<template>
<VueGantt :data="data" />
</template>

Callback Contracts

本节介绍在两种所有权模型中使用的包装器回调形状。

data.save

save 会传递给 gantt.createDataProcessor(save),一次接收一个变更。

典型函数形状:

(entity: string, action: string, data: any, id: string | number) => any

在变更大多为单一且易于逐一处理时使用。

data.batchSave

batchSave 接收按四个数据类型分组的变更:

interface BatchChanges {
tasks?: DataCallbackChange[];
links?: DataCallbackChange[];
resources?: DataCallbackChange[];
resourceAssignments?: DataCallbackChange[];
}

遍历你关心的任意桶 - 包装器会从 Gantt 的逐变更事件自动填充它们。

队列行为摘要:

  • 近端刷新批处理
  • create + update 可以合并为一个带有最新有效载荷的 create
  • create + delete 可以从批处理中移除
  • payload 中会剥离内部的 !nativeeditor_status

在一个用户操作可产生多次更新时使用(例如自动排程)。

ID Remapping And Backend Responsibility

创建操作通常以临时的客户端ID 开始。

  • save 模式下,后端响应应返回持久化的 ID,以便 Gantt 可以重新映射记录。
  • batchSave 模式下,没有逐项返回路径。如果服务器分配了 ID,请在你的持久化工作流中显式处理重新映射。

两种模式下后端职责保持不变:

  • 验证传入的载荷
  • 强制执行权限
  • 持久化权威 ID
  • 返回你所选传输模式期望的数据结构

下一步阅读

Need help?
Got a question about the documentation? Reach out to our technical support team for help and guidance. For custom component solutions, visit the Services page.