在开发思维导图控件blink-mind-react的时候,有一个需求是:当点击展开和折叠某个节点的时候,需要展开和折叠的icon的位置(相对于视口的位置)不要发生变化。
image
这个思维导图组件是放在DragScroll组件里面的,因为思维导图需要可以拖动到视口的任何区域进行查看。在开发思维导图组件的时候,用的布局方式是Flex 布局。当点击展开或者折叠按钮时,整个控件的size会发生变化,而我想要的效果是点击按钮的位置在视觉效果上不能有移动,不然的话,如果点击了按钮之后,发现按钮移动到了另外一个位置(因为整个布局被重排了),用户体验会很差。
为了解决上述问题,想到一个方案是可以在点击按钮之后,调用一个函数让DragScroll控件里面的viewBox的scroll值调整到合适的位置,就可以让点击按钮在视觉上看上去位置没有发生改变。
基于上面的方案,在DragScroll组件里面封装了两个函数:
setViewBoxScroll是使用绝对坐标进行scroll值调整
setViewBoxScrollDelta是使用相对坐标进行scroll值调整
setViewBoxScroll = (left: number, top: number) => {
if (this.viewBox) {
this.viewBox.scrollLeft = left;
this.viewBox.scrollTop = top;
}
};
setViewBoxScrollDelta = (deltaLeft: number, deltaTop: number) => {
if (this.viewBox) {
this.viewBox.scrollLeft += deltaLeft;
this.viewBox.scrollTop += deltaTop;
}
};
通过render函数中的调用传递给子组件
{this.props.children(
this.setViewBoxScroll,
this.setViewBoxScrollDelta
)}
这样子组件就可以通过props 拿到这两个函数,在需要的时候调用这两个函数中的任意一个进行自己所需要的scroll值调整。
比方说在思维导图的节点组件NodeWidget中,使用了setViewBoxScrollDelta函数来调整DragScroll组件的scroll 值,保证节点在展开或折叠过程中,视觉上位置不变。
componentDidUpdate(
prevProps: Readonly<MindNodeWidgetProps>,
prevState: Readonly<MindNodeWidgetState>,
snapshot?: any
): void {
if (this.needRelocation) {
let newRect = this.collapseIcon.getBoundingClientRect();
this.props.setViewBoxScrollDelta(
newRect.left - this.oldCollapseIconRect.left,
newRect.top - this.oldCollapseIconRect.top
);
this.needRelocation = false;
}
this.layoutSubLinks();
}