前言
在用例管理中,文本用例通常是在表单中编写,而有些测试则偏好在本地Xmind中编写测试用例,导致有的用例并不规范。为了解决这一问题,我们引入了Xmind脑图与用例列表视图之间互转的功能,以实现用例的全局管理和高效编写。本篇文章将探讨在集成Xmind脑图功能时,使用kityminder-core遇到的一些问题和技巧,旨在帮助你面临Xmind开发任务时,能够快速上手并避免潜在的坑
一、常用的脑图命令
命令 | 说明 |
---|---|
this.minder.execCommand("ZoomIn"); | 放大脑图 |
this.minder.execCommand("ZoomOut"); | 缩小脑图 |
this.minder.execCommand("Camera", this.minder.getRoot(), 60); | 设置根节点为中心节点 |
this.minder.execCommand('ExpandToLevel', level); | 展开到指定的层级节点 |
this.minder.execCommand('AppendChildNode', {...groupNode,}); | 插入子节点 |
this.minder.execCommand("ArrangeUp"); | 向上移动选中节点 |
this.minder.execCommand('Priority', priority); | 设置优先级 |
更多脑图命令请查看kityminder-core命令说明文档
二、Xmind脑图风格自定义
在kityminder中,脑图只支持他一些自身设定好的主题,用户可以切换不同的主题来达到不同的UI展示效果
比如用例管理最开始是用默认的天空蓝,看起来则有点杂
比如我们切换成浪漫紫呢?看起来好像会好点
js
this.minder.execCommand('Theme', 'fresh-purple');
但是,在用例管理看起来好像还是有点突兀,风格不统一,那我们可不可以自定义一个主题风格呢?
查阅了一下他的使用文档,更多是一些常用的指令和方法的说明,并没有自定义风格主题的说明。于是,clone了它的源码,发现我们上面提到过的主题都是通过theme.register的方法进行配置的
下图则是配置的源代码,与上图的各个风格的关键词也都对上了,于是,我们可以借着这个思路,模仿它创建一个属于我们自己的脑图风格
我们查一下可用的主题列表
javascript
window.kityminder.Minder.getThemeList()
copy他配置主题所需要的参数和方法,调整一下相关的变量
js
import 'kity';
export function hsl(h, s, l) {
return window.kity.Color.createHSL(h, s, l);
}
export function generate(h) {
return {
background: '#fbfbfb',
'root-color': 'black',
'root-background': 'white',
'root-stroke': '#bdc1ce', // 根节点border的颜色
'root-font-size': 16,
'root-padding': [12, 24],
'root-margin': [30, 100],
'root-radius': 5,
'root-space': 10,
'main-color': 'black',
'main-background': 'white', // 一级节点的内容背景色
'main-stroke': '#dcdfe6',
'main-stroke-width': 1.5,
'main-font-size': 14,
'main-padding': [6, 20],
'main-margin': 20,
'main-radius': 3,
'main-space': 5,
'sub-color': 'black',
'sub-background': 'transparent',
'sub-stroke': 'none',
'sub-font-size': 12,
'sub-padding': [5, 10],
'sub-margin': [15, 20],
'sub-radius': 5,
'sub-space': 5,
'connect-color': '#bdc1ce', // 线的颜色
'connect-width': 1,
'connect-radius': 5,
'selected-stroke': '#0052d9', // 节点选中时的颜色
'selected-stroke-width': '3',
'blur-selected-stroke': hsl(h, 10, 60),
'marquee-background': hsl(h, 100, 80).set('a', 0.1),
'marquee-stroke': hsl(h, 37, 60),
'drop-hint-color': hsl(h, 26, 35),
'drop-hint-width': 5,
'order-hint-area-color': hsl(h, 100, 30).set('a', 0.5),
'order-hint-path-color': hsl(h, 100, 25),
'order-hint-path-width': 1,
'text-selection-color': hsl(h, 100, 20),
'line-height': 1.5,
};
}
注册我们的主题"tm-xmind-theme"
js
window.kityminder.Theme.register('tm-xmind-theme', generate(122));
this.minder.execCommand('Theme', 'tm-xmind-theme');
在初次导入数据的时候就设置成我们的主题
js
const data = res.data.data;
data.template = "right";
data.theme = 'tm-xmind-theme';
this.minder.importJson(data);
到这里,我们就注册成功了自己的Xmind主题了,查一下可用主题列表
整体的UI风格就好了许多,也跟我们的网站风格保持了一致
三、资源标签底色对应
在下图中,脑图中的"用例"和上面示例中的"用例"底色对不上,为啥会这样子呢,其他时候展示还好好的
测试了一波发现"回归"标签提前比"用例"标签出现了,主动占据了第二个颜色。看了一下源码,也是按照顺序给标签设置颜色的,于是就出现了标签颜色不对应的情况
我们可以利用getResourceColor,在脑图初始化的时候,就先为标签占个颜色,达到颜色对应的效果
js
this.minder = new window.kityminder.Minder({
renderTo: "#minder-container",
});
this.minder.getResourceColor('分组');
this.minder.getResourceColor('用例');
this.minder.getResourceColor('前置条件');
四、往子节点数组头部插入一个新元素
用例在添加"前置条件"的时候,需要把"前置条件"节点添加到"用例"子节点的顶部
但是kityminder并没有提供这个功能,而是直接往子节点底部或者同级节点添加一个元素
我们可以利用AppendChildNode(插入子节点)和ArrangeUp(向上调整选中节点的位置)这两个命令来把新插入的"前置条件"节点调整到第一个
js
handleAddPrecondition() {
const children = this.selectedNodeOfMinder.children || [];
const id = `前置条件-${Date.now()}`;
this.minder.execCommand('AppendChildNode', {
id,
text: '前置条件',
resource: ['前置条件'],
});
this.minder.selectById(id);
children.forEach(() => {
this.minder.execCommand("ArrangeUp");
});
this.handleUnsavedCaseListData();
},
五、防止用户选中多节点
默认用户可以通过按住control点击多个节点和用鼠标圈范围选中多个节点,但是如果我们想用户只能选中一个节点,然后针对这个节点类型进行对应的操作,需要怎么做呢?
通过查看源码,发现selectById这个方法的第二个参数可以设置节点为单选
于是,我们可以利用用户在触发多选操作时,在selectionchange节点选中的监控方法内去处理完我们需要的处理的逻辑,最后再加上this.minder.selectById(this.selectedNode.id, true);这句就可以了
js
this.minder.on('selectionchange', () => {
// 业务处理逻辑
this.minder.selectById(this.selectedNode.id, true);
});
六、解决某些节点多次双击以后不出现编辑框的问题
比如我们在想修改这种节点,但是有时某些节点会因为需要查询下级节点的数据,导致dblclick事件没有触发,只触发了首次的mousedown鼠标点击事件,所以有一些节点会出现多次双击还是打不开这个编辑输入框的情况
我们可以在首次点击节点,加载了子级数据以后,给这个节点一个loaded为true的标识,这样子用户首次双击会加载子节点数据,其余情况都可以直接双击出现编辑输入框
这里需要注意一个情况,kityminder并没有直接在文档说明给选中节点添加一个字段的命令。为了避免脑图需要重新处理数据/导入数据,查看源码发现了setData方法
js
getData: function(key) {
return key ? this.data[key] : this.data;
},
setData: function(key, value) {
if (typeof key == 'object') {
var data = key;
for (key in data) if (data.hasOwnProperty(key)) {
this.data[key] = data[key];
}
}
else {
this.data[key] = value;
}
return this;
},
/**
* 设置节点的文本数据
* @param {String} text 文本数据
*/
setText: function(text) {
return this.data.text = text;
},
/**
* 获取节点的文本数据
* @return {String}
*/
getText: function() {
return this.data.text || null;
},
所以,我们可以通过这个方法,直接给这个节点添加标识
js
const node = this.minder.getSelectedNode();
node.setData('loaded', true);
七、防止各个不同节点互相拖拽进入彼此节点的情况
比如我们要禁止脑图中不同节点间随意互相拖拽,我们可以怎么做?
kityminder提供了beforeExecCommand执行命令前的监控,而这种节点间可以互相拖拽进入则是因为执行了movetoparent这个命令,我们可以在movetoparent这个命令执行前给它阻断掉即可
js
// 监听脑图执行命令前(可通过e.stopPropagation拦截命令执行)
this.minder.on('beforeExecCommand', (event) => {
console.log('1-zp-event:', event, event.commandName);
if (['movetoparent'].includes(event.commandName)) {
event.stopPropagation();
}
});
八、清除多余的节点选中样式
我们在加载用例节点的前置条件、步骤和预期结果的子节点的时候,是通过AppendChildNode的方法去逐个插入的,插入完成以后通过selectById把选中节点设置会用例节点,但是出现了老的选中节点没有清除样式的情况,比如下面出现了两个选中的样式
记得我们在上文中提到过selectById源码中,第二个参数是可以设置节点为单选的,所以,我们只需要把第二个参数为true即可解决问题
js
this.minder.selectById(nodeId, true);
九、子节点渲染提速
在开发的时候,发现当我们一个分组下有多个子用例和子分组的时候,如果子节点过多,脑图渲染出来子节点所需要消耗的时间需要30秒。如下代码,我们是利用AppendChildNode一个一个去插入子节点的,当子节点数量过多时,这种插入的性能就降低了
js
children.forEach((item, index) => {
this.minder.selectById(item.data.parentId);
// 插入子节点
this.minder.execCommand('AppendChildNode', {
...item.data,
});
});
通过调研、实践,我发现是不是可以把数据处理完成以后再渲染,不要处理一个数据就去动一次脑图,于是通过把数据处理完以后,直接importJson一次性进行渲染,速度马上提升到1秒
js
// 插入子节点数据到大的json数据中,最后再importJson
this.minder.importJson(data);
于是,在处理相关数据的时候,我把子节点低于20条的就使用AppendChildNode的方式去插入子节点,当超过20条的时候,就采用importJson去渲染整个json,最后再选中其加载的节点即可,性能也提升了许多
十、脑图快捷键
我们在使用脑图在编写用例的时候,现在是通过上方的操作按钮去进行不同节点的不同操作的
我们可以利用键盘按钮的相关监控,去处理不同节点类型,使用不同的快捷键去快速处理脑图的行为
js
handleShortcutKeyEvent: throttle(function (event) {
switch (event.code) {
case 'Enter':
if (!this.groupOpeDisabled) {
this.handleAddGroup();
}
break;
case 'Tab':
if (this.isGroupNode && this.hasModuleRight) {
this.handleAddCase();
}
if (this.isCaseNode && this.hasModuleRight) {
this.handleAddStep();
}
break;
case 'Space':
if (!this.editOrDeleDisabled) {
this.handleEditNode();
}
break;
case 'Backspace': // Backspace、Delete都触发删除
case 'Delete':
if (!this.editOrDeleDisabled) {
this.handleDeleteNode();
}
break;
case 'KeyS':
if ((event.ctrlKey || event.metaKey)) {
this.handleSaveCaseList();
}
break;
default:
break;
}
}, 1500),
keydownListener(event) {
// 编辑状态,直接不处理快捷键相关逻辑
if (this.inputNodeVisible) {
return;
}
// 立即阻止默认行为,以确保它在事件冒泡之前被处理
if (event.code === 'Tab' || event.code === 'Space' || event.code === 'KeyS') {
event.preventDefault();
}
this.handleShortcutKeyEvent(event);
},
js
document.addEventListener('keydown', this.keydownListener);
当然,在页面销毁时,记得销毁
js
document.removeEventListener('keydown', this.keydownListener);
在脑图进行快捷键进行快捷操作时,记得考虑好一个快捷键,在不同的节点下触发,会对应着什么行为,比如模块节点、分组节点、用例节点、前置条件节点、步骤节点和预期结果节点
十一、总结
本文介绍了在开发Xmind脑图时,使用kityminder的一些技巧和常见问题处理,希望在大家开发脑图相关需求的时候,能够快速上手并避免潜在的坑