Skip to content

样式与扩展

定制应从成本最低、契约最稳定的入口开始:先调整主题令牌与尺寸,再使用 Resolver 修改几何和算法,只有业务结构确实不同才替换 Slot、Render Prop 或 Builder。这样能最大限度保留虚拟化、拖放与无障碍行为。

选择扩展层级

目标推荐入口保留的内置能力
颜色、圆角、行高、任务条高度主题令牌与尺寸参数全部
按任务决定宽高、纹理或依赖线样式Layout / Style / Effect Resolver几何、交互与虚拟化
自定义财务周、班次或不等宽时间格Timeline Resolver坐标转换、吸附与聚焦
替换任务内容或宿主业务控件Slot / Render Prop / Builder可见窗口与事件协议

自定义入口应保持纯计算或轻量渲染。不要在每个可见任务中创建独立观察器、复杂滤镜或不受预算限制的持续动画。

Vue 插槽

组件开放表头、任务信息、负责人、进度、任务条、纹理层、动效层、依赖线、空状态、工具条和行级边缘按钮插槽。

vue
<YgGantt :tasks="tasks">
  <template #bar="{ task, progress }">
    <MyTaskBar :task="task" :progress="progress" />
  </template>

  <template #edge-indicator="{ task, side, jump }">
    <button type="button" @click="jump">
      {{ side === 'left' ? '←' : '→' }} {{ task.title }}
    </button>
  </template>
</YgGantt>

barLayoutResolver 可以按任务、维度与几何结果修改任务条高度、最小宽度和圆角。dependencyPathResolverdependencyStyleResolver 可接管依赖线路径与样式。

自定义时间维度与表头

IMPORTANT

本节 Resolver API 已进入 Core alpha.2、Vue alpha.5、React alpha.1 源码候选版。当前 npm alpha 标签尚未包含它们,以发布与兼容性页面的 Registry 版本为准。

Web 端把时间轴定制拆成两个层级,避免为了改一个标题复制整套日期算法:

  • timelineLabelResolver 只替换上下两层表头文字,适合财务周、冲刺编号、班次和本地化。
  • timelineResolver 接收 Core 生成的 defaultTimeline,可以替换时间格、分组、宽度或完整模型,适合 4-4-5 财务日历、生产班次和企业专用周期。

只修改内置维度的表头:

ts
const timelineLabelResolver: TimelineLabelResolver = ({
  view,
  tier,
  cell,
  defaultLabel,
}) => {
  if (view === 'week' && tier === 'upper') {
    return `Sprint · ${defaultLabel}`
  }
  if (view === 'week' && tier === 'lower') {
    return `${cell.start.getMonth() + 1}/${cell.start.getDate()}`
  }
  return defaultLabel
}

定义专用时间格:

ts
const timelineResolver: TimelineResolver = ({ view, defaultTimeline }) => {
  if (view !== 'week') return defaultTimeline

  let x = 0
  const cells = defaultTimeline.cells.map((cell) => {
    const width = cell.weekend ? 36 : 88
    const next = { ...cell, x, width }
    x += width
    return next
  })

  return { cells, width: x }
}

当 Resolver 只返回 cells 时,Core 会按日期交集重新计算上层分组的 xwidth;如果你的分组语义也不同,可以同时返回 upperCellsdateToXxToDate、拖放吸附、边缘跳转和自动定位都会使用解析后的模型。

vue
<YgGantt
  :tasks="tasks"
  :timeline-resolver="timelineResolver"
  :timeline-label-resolver="timelineLabelResolver"
/>
tsx
<YgGantt
  tasks={tasks}
  timelineResolver={timelineResolver}
  timelineLabelResolver={timelineLabelResolver}
/>

如果宿主需要一个不出现在内置六档切换器中的专用维度,可以关闭 showToolbar,在宿主工具栏里维护当前模式,并让 timelineResolver 根据该模式返回对应模型。这样不会扩大 ViewPresetId,联动协议仍然保持稳定。

React Render Props

tsx
<YgGantt
  tasks={tasks}
  renderBar={({ task, progress, selected }) => (
    <TaskBar task={task} progress={progress} selected={selected} />
  )}
  renderEdgeIndicator={({ task, side, jump }) => (
    <button type="button" onClick={jump}>{side} · {task.title}</button>
  )}
/>

renderDependency 可替换完整 SVG 路径;renderTaskrenderOwnerrenderProgress 可接入宿主任务表组件。

Flutter Builder

dart
YotsubaGantt(
  tasks: tasks,
  taskBarBuilder: (context, details) {
    return ColoredBox(
      color: details.task.color ?? Colors.green,
      child: Text(details.task.title),
    );
  },
  rowHeaderBuilder: (context, task, rowIndex) {
    return ListTile(dense: true, title: Text(task.title));
  },
  entryTransitionBuilder: (context, child, animation) {
    return FadeTransition(opacity: animation, child: child);
  },
  edgeIndicatorBuilder: (context, details) {
    return IconButton(
      onPressed: details.jump,
      icon: Icon(details.side == YgEdgeSide.left
        ? Icons.chevron_left
        : Icons.chevron_right),
    );
  },
)

默认动效只使用 transformopacity 或描边偏移,并受视口预算控制。宿主可以关闭内置过渡,或通过插槽、Builder 和 CSS 自行实现效果。

MIT License · Vue / React / Flutter