上个版本的标签栏实现了标签切换以及右键菜单性能。这几天利用闲余工夫加上了拖动性能:
GitHub
次要参考了 React 实现繁难的图片拖动排序
实现思路
本来想应用 onDragStart/onDragOver/onDragEnd
事件来实现,但因为标签的款式实现形式影响,拖动进去的款式乱掉了,因而 pass 掉,还是应用 onMouseDown/onMouseMove/onMouseEnd
实现:
-
每一个标签监听
onMouseDown
事件- 记录以后点击的标签(
movingTagPath
) - 一些地位(
originMousePos/originTagPos
) - 设置以后标签为选中状态
- 记录以后点击的标签(
-
document
监听mousemove
及mouseup
事件mousemove
处理函数中计算挪动的间隔,(解决边界值后)设置movingTagPos
mouseup
处理函数中重置movingTagPos/movingTagPath
并移除document
监听的事件
-
标签父元素监听
onMouseMove
事件- 解决拖动过程中标签地位更新逻辑
//onMouseDown handler
const onTagMouseDown = useCallback((e, path) => {e.preventDefault();
movingTagPath.current = path;
const x = (parseInt(e.currentTarget.style.left, 10) || 0);
originMousePos = {x: e.pageX, y: 0};
originTagPos = ({x, y: 0});
const activeTag = contentDivRef.current?.querySelector(`.${style.active}`);
activeTag?.setAttribute('class', style.tagC);
e.currentTarget?.classList.add(style.active);
e.currentTarget?.classList.add(style.moving);
setMovingTagPos({x: 0, y: 0});
document.addEventListener('mousemove', onTagMouseMove);
document.addEventListener('mouseup', onTagMouseUp);
}, [onTagMouseMove, onTagMouseUp]);
// mousemove 及 mouseup
const onTagMouseMove = useCallback((e) => {e.preventDefault();
const contentWidth = (contentDivRef.current?.getBoundingClientRect().width || 0);
const contentLeft = (contentDivRef.current?.getBoundingClientRect().left || 0);
// 边界值解决
const threshold = (contentLeft + (TAG_WIDTH / 2));
if (e.pageX < threshold) {setMovingTagPos({ x: 0, y: 0});
return;
}
let x = e.pageX - originMousePos.x + originTagPos.x;
x = x > contentWidth - threshold ? contentWidth - threshold : x;
setMovingTagPos({x, y: 0});
}, []);
const onTagMouseUp = useCallback(() => {document.removeEventListener('mousemove', onTagMouseMove);
document.removeEventListener('mouseup', onTagMouseUp);
setMovingTagPos({x: 0, y: 0});
movingTagPath.current = '';
}, [onTagMouseMove]);
// onMouseMove handler
const onTagOver = useCallback((e) => {e.preventDefault();
updateTags(e.clientX);
}, [updateTags]);
const updateTags = useCallback((clientX: number) => {const dropRect = contentDivRef.current?.getBoundingClientRect();
if (dropRect && movingTagPath.current) {
const offsetX = clientX - dropRect.left;
const dragItem = tags.find((item) => item.path === movingTagPath.current) || {path: '', title:''};
const col = Math.floor(offsetX / TAG_WIDTH);
let currentIndex = col;
const fromIndex = tags.indexOf(dragItem);
if (fromIndex < currentIndex) {currentIndex += 1;}
const currentItem = tags[currentIndex];
const ordered = insertBefore(tags, dragItem, currentItem);
if (isEqualBy(ordered, tags, 'path')) return;
// 改正更换程序后标签地位偏移
if (fromIndex < currentIndex) {originMousePos.x += TAG_WIDTH;} else {originMousePos.x -= TAG_WIDTH;}
setTags(ordered);
}
}, [tags]);