kd-lane-container
v0.1.3
Published
kd-lane-container
Downloads
254
Readme
KdLaneContainer 组件使用文档
1. 组件概述
KdLaneContainer 是一个基于 Vue 开发的泳道图容器组件,用于展示和管理泳道模板、线条配置等。
1.1 设计思路
- 逻辑分离:将模板、泳道、参数的设置逻辑和绘制逻辑完全剥离,提高组件的可维护性和扩展性
- 接口兼容:提供了不依赖接口但是兼容接口实现的模板配置逻辑,既支持本地静态数据直接使用,也支持对接后端接口
- 使用场景:
- 适合静态数据展示场景,无需后端接口即可运行
- 适合合作单位使用,提供灵活的数据接入方式
- 技术栈无关:不限制绘制区技术栈,绘制逻辑完全由外部实现,只需要监听组件事件即可动态调整绘制内容
1.2 组件更名说明
重要通知:从版本 0.0.8 开始,组件名称正式从 KdLaneChartContainer 更名为 KdLaneContainer
更名必要性:
- 更准确的功能定位:原名称包含 "Chart"(图表),但组件实际上是一个通用的泳道容器,不直接负责图表绘制,更名后更符合其实际功能定位
- 简化命名:去掉冗余的 "Chart" 后缀,使组件名称更简洁易记
- 避免语义混淆:澄清了组件职责边界,明确表示这是一个容器组件而非图表组件,避免与其他图表组件混淆,和包名保持一致
版本兼容性:
- 版本 0.0.8 及以后:统一使用
KdLaneContainer - 版本 0.0.7 及之前:使用旧名称
KdLaneChartContainer
2. 组件功能
- 加载和展示泳道模板
- 支持自定义泳道头部
- 提供上下文菜单操作
- 支持自定义菜单扩展
- 实时曲线配置功能
- 模板和线条的增删改查操作
3. 组件引入
3.1 安装与注册
// 安装依赖
// npm install kd-lane-container --save
// 引入组件
import KdLaneContainer from "kd-lane-container";
import Vue from "vue";
// 注册组件
Vue.use(KdLaneContainer);3.2 在组件中使用
export default {
// 组件已全局注册,无需再局部注册
// components: {},
// ...
};4. 组件使用
4.1 基本使用
4.1.1 泳道宽度配置
从版本 0.1.0 开始,支持通过 width 属性自定义泳道宽度。
配置说明:
- 自定义插槽泳道:
- 如果泳道配置中包含
width属性(数字类型),则动态设置style为width: ${width}px。 - 如果未配置
width,则动态设置style为width: auto,由插槽内容决定实际宽度(之前的默认逻辑)。
- 如果泳道配置中包含
- 普通泳道:
- 如果泳道配置中包含
width属性(数字类型),则动态设置style为width: ${width}px。 - 如果未配置
width,则动态设置style为flex: 1,与其他未设置宽度的泳道平分剩余空间(之前的默认逻辑)。
- 如果泳道配置中包含
示例配置:
lanes: [
{ 其他属性..., width: 200 }, // 自定义宽度为 200px
{ 其他属性..., } // 未设置宽度,使用默认逻辑
]4.1.2 泳道尺寸获取
新增 getGridSize 方法,用于获取泳道的精确尺寸(包括泳道抬头部分)。
注意事项:
- 调用时机:需确保泳道容器的
div已挂载并渲染完毕,否则可能返回空数组或错误数据。 - 返回值:返回泳道的
x、y、width、height等尺寸信息,以及lane-id属性。
示例代码:
const gridSizes = this.$refs.laneContainer.getGridSize();
console.log(gridSizes); // 输出泳道尺寸信息<KdLaneContainer
class="container"
:config="config"
:customMenuList="customMenuList"
@onCustomMenuClicked="onCustomMenuClicked"
@template-change="templateChange"
@line-change="lineChange"
:themeName="themeName"
>
<!-- 动态slot,处理容器抬头自定义布局 -->
<template v-if="headerSlotName">
<div :slot="headerSlotName" class="header-slot">
{{ headerSlotName }}
</div>
</template>
<!-- 处理draw-slot中泳道div -->
<template v-if="lanes && lanes.length > 0" slot="draw-slot">
<div class="draw-slot">
<template v-for="lane in lanes">
<!-- 如果title定义了,需要和title保持一样宽度 -->
<div v-if="lane.laneKey == 'depth'" :key="lane.laneId" style="width: 80px; height: 100%; overflow: hidden">
{{ lane.laneKey }}
</div>
<!-- 平分的泳道布局 -->
<div v-else class="lane-div" :key="`lane-${lane.laneId}`">
{{ lane.laneId }}
</div>
</template>
</div>
</template>
</KdLaneContainer>使用步骤说明
配置组件:
- 通过
config属性传入初始配置,包括数据源类型、案例ID、版本号等。 - 通过
customMenuList属性传入自定义菜单列表。
- 通过
监听事件动态渲染:
- 监听
template-change事件,获取最新的泳道数据(lanes),动态渲染自定义抬头和泳道布局。 - 监听
line-change事件,处理线条配置的变化。从版本 0.1.1 开始,该事件会传递包含actionType属性的线条对象,可用于区分新增/更新和删除操作。
- 监听
主题变化处理:
- 主题变更是由外部触发的,组件仅负责根据
themeName属性正确渲染标题。 - 模板和线条的变化需要自行处理,组件不会主动通知这些变化。
- 主题变更是由外部触发的,组件仅负责根据
线条变更事件处理示例
// 在组件方法中处理 line-change 事件
lineChange(line) {
console.log('线条变更事件:', line);
// 根据 actionType 区分操作类型
switch (line.actionType) {
case 'upsertLine':
console.log('新增或更新线条:', line);
// 处理线条新增或更新逻辑
break;
case 'delLine':
console.log('删除线条:', line);
// 处理线条删除逻辑
break;
default:
console.log('未知操作类型:', line.actionType);
}
}4.2 场景与版本控制
4.2.1 场景唯一标识规则
- caseId (场景 ID):用于唯一标识不同的应用场景或业务模块。
- 必须确保在同一应用中唯一,否则会导致数据混淆。
- 建议使用业务模块名称或唯一的 UUID。
- 所有数据操作都将与该场景 ID 绑定,确保数据隔离。
4.2.2 版本号管理
- versionCode (版本号):用于管理不同版本的初始配置。
- 当业务需求发生重大变更时,可以通过升级版本号来重置数据。
- 版本号升级后,系统会自动清理旧版本数据并重新初始化。
- 版本号必须为整数,建议从 1 开始递增。
4.2.3 数据初始化策略
- 首次初始化:系统会将传入的
dataSource保存为当前版本的初始配置。 - 版本冲突:当检测到版本号变更时,系统会自动重置数据并使用新版本的配置。
- 异常恢复:如果初始化过程中出现错误,系统会自动执行重置操作。
4.3 配置参数
4.3.1 数据源类型选择说明
KdLaneContainer 支持两种数据源类型:
- local:无后台配置接口,仅需前端单方面维护配置时使用
- custom:需要本组件 + 后台实时曲线配置接口组合使用时使用
4.3.2 本地数据源 (Local)
config: {
type: "local", // 数据源类型,可选值: "local" | "custom"
caseId: "demo", // 案例ID
versionCode: 2, // 版本号
dataSource: { // 数据源
// 支持两种数据结构:
// 1. 扁平结构 (推荐用于数据量大的场景)
templates: [], // 模板数据
lanes: [], // 泳道数据
lines: [], // 线条数据
params: [] // 参数数据
// 2. 树形结构 (直观易读,不用关心数据ID,组件会自己补全和维护)
// templates: [{
// lanes: [{
// lines: []
// }]
// }],
// params: []
}
}local 模式下 datasource 参数说明:
- templates:只需提供
templateName属性 - lane:不需要提供任何属性
- line:需要提供以下属性:
paramId,min,lineSort,max,lineSize,lineColor,lineType,isUsed可选属性:themeConfig- 线条级别主题颜色配置,支持为不同主题设置不同的线条颜色;isGradient- 是否为渐变线条。当设置为 true 时:- lineType 必须为 "area"避免歧义
- lineColor 和 themeConfig 中的 lineColor 应使用 linear-gradient 格式
- LineEdit 组件中的颜色选择器和线型选择器将被禁用
示例:
{ paramId: "52", min: 0.001, max: 100, lineSort: 1, lineSize: "2", lineColor: "linear-gradient(to bottom, blue, red)", lineType: "area", isUsed: "1", isGradient: true, themeConfig: { white: { lineColor: "linear-gradient(to bottom, black, red)" }, dark: { lineColor: "linear-gradient(to bottom, yellow, red)" }, gray: { lineColor: "linear-gradient(to bottom, #E5360B, red)" } } }
- params:需要提供以下属性:
paramId,paramName,paramUnit示例:{ paramId: "12", paramName: "钻头位置", paramUnit: "m" }
完整 local 模式示例配置:
config: {
type: "local",
caseId: "demo",
versionCode: 2,
dataSource: {
// 嵌套结构示例
templates: [
{
templateName: "测试",
lanes: [
{
lines: [
{ paramId: "51", min: 0.001, lineSort: 1, max: 100, lineSize: "2", lineColor: "#E5360B", lineType: "solid", isUsed: "1", isGradient: false, themeConfig: { white: { lineColor: "blue" }, dark: { lineColor: "black" }, gray: { lineColor: "yellow" } } },
{ paramId: "52", min: 0.001, lineSort: 2, max: 100, lineSize: "2", lineColor: "linear-gradient(to bottom, blue, red)", lineType: "area", isUsed: "1", isGradient: true, themeConfig: { white: { lineColor: "linear-gradient(to bottom, black, red)" }, dark: { lineColor: "linear-gradient(to bottom, yellow, red)" }, gray: { lineColor: "linear-gradient(to bottom, #E5360B, red)" } } }
]
}
]
}
],
params: [
{ paramId: "51", paramName: "钻头位置", paramUnit: "m" },
{ paramId: "52", paramName: "钻压", paramUnit: "kN" }
]
}
}4.3.3 自定义数据源 (Custom)
config: {
type: "custom", // 数据源类型,可选值: "local" | "custom"
caseId: "demo", // 案例ID
versionCode: 2, // 版本号
// 自定义数据源必须实现的7个方法,需按照要求的返回格式设置
getUserTemplates() { /* 加载所有模板、泳道和线条数据 */ },
upsertTemplate(data) { /* 新增或更新模板 */ },
delTemplate(data) { /* 删除模板 */ },
upsertLane(data) { /* 新增或更新泳道 */ },
delLane(data) { /* 删除泳道 */ },
upsertLine(data) { /* 新增或更新线条 */ },
delLine(data) { /* 删除线条 */ },
// 可选方法:恢复默认设置 【**在local模式下,可以通过this.$refs[xxx].restoreSetting()方法恢复默认设置**】
restoreSetting() { /* 恢复默认设置 */ }
}各方法参数和返回值说明:
getUserTemplates()- 返回值:
Promise<Object>- 包含所有模板、泳道和线条数据的配置对象 - 示例:
{ "caseVersion": { "caseId": "case123", "versionCode": "v1.0" }, "templates": [ /* 模板数组 */ ], "params": [] }
- 返回值:
upsertTemplate(data)- 参数:
data- 模板数据 - 返回值:
Promise<Object>- 插入或更新后的完整模板对象
- 参数:
delTemplate(data)- 参数:
data- 模板数据(需包含templateId) - 返回值:
Promise<void>- 操作成功或失败的 Promise
- 参数:
upsertLane(data)- 参数:
data- 泳道数据 - 返回值:
Promise<Object>- 插入或更新后的完整泳道对象
- 参数:
delLane(lane)- 参数:
lane- 泳道数据(需包含laneId和lines数组) - 返回值:
Promise<void>- 操作成功或失败的 Promise
- 参数:
upsertLine(data)- 参数:
data- 线条数据 - 返回值:
Promise<Object>- 插入或更新后的完整线条对象
- 参数:
delLine(data)- 参数:
data- 线条数据(需包含lineId和laneId) - 返回值:
Promise<void>- 操作成功或失败的 Promise
- 参数:
restoreSetting()(可选)- 返回值:
Promise<void>- 恢复默认设置的 Promise
- 返回值:
4.4 自定义菜单
customMenuList 用于在上下文菜单中添加自定义操作选项。当用户在泳道头部或线条上右键点击时,这些自定义选项会出现在上下文菜单中。
4.4.1 菜单结构
customMenuList: [
{
name: "单屏时长", // 菜单项显示名称
key: "timeRange", // 菜单项唯一标识
},
{
name: "导出数据",
key: "exportData",
},
];4.4.2 点击事件
当用户点击自定义菜单项时,会触发 onCustomMenuClicked 事件,并传递以下参数:
event: 事件对象,包含option和item属性option: 被点击的菜单项配置item: 右键点击时的目标对象(可能是泳道或线条)
4.4.3 使用示例
<KdLaneContainer
:customMenuList="[{ name: '单屏时长', key: 'timeRange' }]"
@onCustomMenuClicked="handleCustomMenuClick">
</KdLaneContainer>handleCustomMenuClick(event) {
const { option, item } = event;
console.log('自定义菜单项被点击:', option.name);
console.log('点击的目标对象:', item);
if (option.key === 'timeRange') {
// 处理单屏时长操作
}
}5. 组件 API
5.1 Props
| 属性名 | 类型 | 默认值 | 说明 | | ---------------- | ------ | ------- | ------------------ | | config | Object | 必填 | 组件配置对象 | | headerPadding | Number | 4 | 泳道头部内边距 | | headerItemHeight | Number | 20 | 头部线条项高度 | | itemGap | Number | 2 | 线条项之间的间距 | | customMenuList | Array | [] | 自定义菜单列表 | | themeName | String | "white" | 当前使用的主题名称 |
5.2 事件
| 事件名 | 参数 | 说明 | | ------------------- | -------- | ------------------ | | onCustomMenuClicked | event | 自定义菜单点击事件 | | line-change | line | 线条变化事件 | | template-change | template | 模板变化事件 |
line-change 事件参数说明:
- 从版本 0.1.0 开始,
line-change事件会传递包含actionType属性的线条对象 actionType标识操作类型,可能的值为:"upsertLine"- 新增或更新线条操作"delLine"- 删除线条操作
5.3 方法
5.3.1 组件实例方法
| 方法名 | 作用描述 | 入参 |
|----------------|-------------------------------------------------------------------------|------|
| getGridSize | 获取泳道的精确尺寸(包括泳道抬头部分) | 无 |
| restoreSetting | 恢复组件的初始设置(如重置模板、泳道和线条配置到默认状态) | 无 |
5.3.2 数据源方法(仅 custom 模式需要实现)
注:以下方法仅在使用 custom 模式时需要了解和实现,local 模式下不需要考虑。
组件内部提供的方法主要用于模板和线条的管理:
upsertTemplate(data) - 新增或更新模板
- 参数:
data- 模板数据 - 返回值:
Promise<Object>- 插入或更新后的完整模板对象
- 参数:
delTemplate(data) - 删除模板
- 参数:
data- 模板数据(需包含templateId) - 返回值:
Promise<void>- 操作成功或失败的 Promise
- 参数:
upsertLane(data) - 新增或更新泳道
- 参数:
data- 泳道数据 - 返回值:
Promise<Object>- 插入或更新后的完整泳道对象
- 参数:
delLane(lane) - 删除泳道
- 参数:
lane- 泳道数据(需包含laneId和lines数组) - 返回值:
Promise<void>- 操作成功或失败的 Promise
- 参数:
upsertLine(data) - 新增或更新线条
- 参数:
data- 线条数据 - 返回值:
Promise<Object>- 插入或更新后的完整线条对象
- 参数:
delLine(data) - 删除线条
- 参数:
data- 线条数据(需包含lineId和laneId) - 返回值:
Promise<void>- 操作成功或失败的 Promise
- 参数:
restoreSetting() - 恢复默认设置
- 功能:将当前场景的数据重置为初始配置状态
- 实现逻辑:使用构造函数传入的初始 dataSource 重新初始化数据
- 返回值:
Promise<void>- 恢复默认设置的 Promise
6. 自定义插槽
组件支持根据泳道 ID 动态生成的插槽,用于自定义泳道头部:
<KdLaneContainer ...>
<!-- 动态slot名称 -->
<template v-if="slotName">
<div :slot="slotName" class="demo-slot">
{{ slotName }}
</div>
</template>
<!-- 带参数的插槽 -->
<template v-if="slotName2" :slot="slotName2" slot-scope="slotData">
<div class="demo-slot">{{ typeof slotData }}</div>
</template>
</KdLaneContainer>插槽名称格式为 lane${laneId},例如:lane1556bdbfd0f24c11948b14999947c556。
6.1 draw-slot 画布插槽
组件提供 draw-slot 插槽用于自定义绘制内容,该插槽占据泳道下方的整个绘制区域:
<KdLaneContainer ...>
<template slot="draw-slot">
<div style="height: 100%; width: 100%; padding: 10px">
<!-- 自定义绘制内容 -->
</div>
</template>
</KdLaneContainer>6.2 插槽布局与尺寸注意事项
布局方式:
- 自定义插槽与泳道区域采用 flex 布局
- 自定义插槽会占据剩余位置后,与其他泳道进行平分
- 确保自定义插槽内容的宽度和高度设置正确,以保证与泳道对齐
尺寸单位:
- 组件内的自定义插槽使用 style 绑定形式
- 宽度和高度单位必须使用 px,以确保精确对齐
- 避免使用其他单位(如 %、rem、em 等),否则可能导致布局错位
样式处理:
- 不要使用全局样式处理插件对自定义插槽的尺寸单位进行转换
- 直接使用 px 单位编写插槽内容的尺寸样式
- 确保插槽内容的 box-sizing 为 border-box,以避免 padding 和 border 影响实际尺寸
<!-- 推荐的插槽内容样式 -->
<template slot="draw-slot">
<div style="height: 100%; width: 100%; box-sizing: border-box; padding: 10px">
<!-- 自定义绘制内容 -->
</div>
</template>7. 主题与样式定制
7.1 组件级 CSS 变量
可以通过 CSS 变量或直接覆盖样式来自定义组件外观:
组件提供了以下 CSS 变量用于主题适配:
| 变量名 | 默认值 | 说明 |
| ---------------------------------------------------- | --------- | ---------------------- |
| --kd-lane-container-border-color | #333 | 组件边框颜色 |
| --kd-lane-container-header-item-color | #333 | 头部线条项文字颜色 |
| --kd-lane-container-context-background-color | #ecf0f1 | 上下文菜单背景色 |
| --kd-lane-container-context-item-color | #333 | 上下文菜单文字颜色 |
| --kd-lane-container-context-hover-background-color | #007aff | 上下文菜单悬停背景色 |
| --kd-lane-container-context-hover-item-color | #fff | 上下文菜单悬停文字颜色 |
| --kd-lane-container-context-divider-color | #595a5a | 上下文菜单分割线颜色 |
7.2 CSS 变量使用示例
.kd-lane-container {
--kd-lane-container-border-color: white;
--kd-lane-container-context-background-color: darkgray;
--kd-lane-container-header-item-color: white;
}7.3 线条级别主题配置
组件支持通过 themeName 属性设置当前主题,配合 line 的 themeConfig 来实现表头线条和图表线条颜色主题适配。
<KdLaneContainer
:themeName="themeName"
...
>每个线条对象可以通过 themeConfig 属性配置不同主题下的颜色,格式为:
themeConfig: {
[themeName]: { lineColor: "颜色值" },
...
}示例:
lines: [
{
paramId: "51",
lineColor: "#E5360B", // 默认颜色
themeConfig: {
white: { lineColor: "blue" }, // 白色主题颜色
dark: { lineColor: "black" }, // 暗黑主题颜色
gray: { lineColor: "yellow" }, // 灰色主题颜色
},
},
];当组件的 themeName 变化时,线条会自动应用对应主题的颜色。如果未配置 themeConfig,则使用默认的 lineColor。
8. 使用示例
<template>
<div id="app">
<KdLaneContainer class="container" :config="config" :customMenuList="customMenuList" @onCustomMenuClicked="onCustomMenuClicked">
<!-- 动态slot名称,这里全部使用的是旧语法 -->
<template v-if="slotName">
<div :slot="slotName" class="demo-slot">
{{ slotName }}
</div>
</template>
<template v-if="slotName2" :slot="slotName2" slot-scope="slotData">
<div class="demo-slot">{{ typeof slotData }}</div>
</template>
</KdLaneContainer>
</div>
</template>
<script>
import Vue from "vue";
import KdLaneContainer from "kd-lane-container";
Vue.use(KdLaneContainer);
import { data } from "./mock/mockData.js";
export default {
name: "App",
components: {},
data() {
return {
config: {
type: "local",
caseId: "demo",
versionCode: 2,
// for with server
dataSource: { templates: data.templates, lanes: data.lanes, lines: data.lines, params: data.params },
},
slotName: "",
slotName2: "",
customMenuList: [{ name: "单屏时长", key: "timeRange" }],
};
},
mounted() {
setTimeout(() => {
this.slotName = "lane1556bdbfd0f24c11948b14999947c556";
}, 2000);
},
methods: {
onCustomMenuClicked(event) {
console.log(event);
},
},
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
height: 100vh;
position: relative;
padding: 10px;
.container {
margin-left: 100px;
margin-top: 50px;
height: 600px;
width: 800px;
}
.demo-slot {
width: 80px;
}
}
/* 全局设置 box-sizing 为 border-box */
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
</style>