本文章系列将会记录在做kityminder二次开发过程中,遇到的问题以及解决方法
有同事反馈在测试用例的任务执行过程中,有的时候会遗漏掉几个用例没有执行,但是找了半天就是找不到在哪里。所以希望能够有一个功能支持快速的过滤(收缩)不需要的用例,保留需要的用例内容。
思考
这个时候考虑的就是类似于脑图展开的功能,能够快速的展开一级菜单/二级菜单,所以我们需要做的就是当用户点击仅未执行用例时,将其他成功,失败等的用例进行收起,仅展开未执行的用例即可,类似于下图:
上图我们就是点击了上面的阻塞,就会将其他节点收起,只展开阻塞部分的用例内容。
那整体的流程应该是怎么样的呢? 因为考虑到这个是一个协同编辑情况,所以最好的方式就是直接通过服务端计算出从当前的脑图数据到过滤后的脑图数据的diff , 然后将patch 的数据分发给各个端即可。
所以我们的流程大致如下:
这个逻辑理论上看上去 其实很ok,没啥问题,并且在本地环境测试了下也是一切良好。
结果上线以后就翻车了,在数据量比较大的时候,一旦进行数据过滤时前端就会load上很久,而且数据量越大,整个浏览器就会相当于卡死的状态。
通过排查发现,后台在计算diff这块的耗时基本可以忽略不计了,所以问题所在的地方其实就是patch的逻辑上了,我们需要去看下 patch
applyPatch 的逻辑中涉及到了 minder.layout(); 这其实是一个很重的动作,然而我们patches数据对象是是非常大的,这种导致了 applyPatch 就会非常的久了。
正在一筹莫展之时,突然想起其实我们本身脑图里面也有同时收起/展开节点的功能。 如下图:
所以立马去了解了下本身这块的逻辑的实现。
var ExpandToLevelCommand = kity.createClass('ExpandToLevelCommand', {
base: Command,
execute: function (km, level) {
km.getRoot().traverse(function (node) {
if (node.getLevel() < level) node.expand();
if (node.getLevel() == level && !node.isLeaf()) node.collapse();
});
km.refresh(100);
},
enableReadOnly: true
});
这里我们就恍然大悟了,涉及到这块的逻辑,其实都是在前端自己本身处理,然后直接到minder中,这里并没有用到patch的逻辑。
解决
所以下来的操作也就比较简单了,就是把原本属于后台的逻辑改到由脑图的前端去完成这块的逻辑处理。
我们自定义了一个minder的过滤节点命令来做这块的逻辑。 这里就直接贴了代码了。
expand.js
var FilterNodeCommand = kity.createClass("FilterNodeCommand", {
base: Command,
execute: function (km, progress) {
function updateNodeExpandState(node, state) {
if (!(state === STATE_EXPAND && typeof (node.getData(EXPAND_STATE_DATA)) === 'undefined')) {
node.setData(EXPAND_STATE_DATA, state);
}
}
function expandNode(node) {
updateNodeExpandState(node, STATE_EXPAND);
for (var i =0; i<node.getChildren().length; i++) {
expandNode(node.getChildren()[i]);
}
}
function isNeedExpand(node, progress) {
var data = node.getData();
if (typeof (data[PROGRESS_DATA]) === 'undefined') {
if (node.getChildren().length === 0) {
return progress == DEFAULT_VALUE;
} else {
var isNeedExpandFlag = false;
for (var i =0; i<node.getChildren().length; i++) {
if (isNeedExpand(node.getChildren()[i], progress)) {
updateNodeExpandState(node.getChildren()[i], STATE_EXPAND);
if (!isNeedExpandFlag) {
isNeedExpandFlag = true;
}
}
}
if (isNeedExpandFlag) {
return true;
} else {
updateNodeExpandState(node, STATE_COLLAPSE);
}
}
} else if (data[PROGRESS_DATA] === progress) {
expandNode(node);
return true;
} else {
updateNodeExpandState(node, STATE_COLLAPSE);
return false;
}
}
var rootNode = km.getRoot();
isNeedExpand(rootNode, progress);
rootNode.setData(EXPAND_STATE_DATA, STATE_EXPAND);
km.refresh(100);
},
enableReadOnly: true
})
|