上个版本的标签栏实现了标签切换以及右键菜单性能。这几天利用闲余工夫加上了拖动性能:
GitHub
次要参考了React 实现繁难的图片拖动排序
实现思路
本来想应用onDragStart/onDragOver/onDragEnd
事件来实现,但因为标签的款式实现形式影响,拖动进去的款式乱掉了,因而pass掉,还是应用onMouseDown/onMouseMove/onMouseEnd
实现:
每一个标签监听
onMouseDown
事件- 记录以后点击的标签(
movingTagPath
) - 一些地位(
originMousePos/originTagPos
) - 设置以后标签为选中状态
- 记录以后点击的标签(
document
监听mousemove
及mouseup
事件mousemove
处理函数中计算挪动的间隔,(解决边界值后)设置movingTagPos
mouseup
处理函数中重置movingTagPos/movingTagPath
并移除document
监听的事件
标签父元素监听
onMouseMove
事件- 解决拖动过程中标签地位更新逻辑
//onMouseDown handlerconst 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及mouseupconst 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 handlerconst 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]);