上个版本的标签栏实现了标签切换以及右键菜单性能。这几天利用闲余工夫加上了拖动性能:

GitHub

次要参考了React 实现繁难的图片拖动排序

实现思路

本来想应用onDragStart/onDragOver/onDragEnd事件来实现,但因为标签的款式实现形式影响,拖动进去的款式乱掉了,因而pass掉,还是应用onMouseDown/onMouseMove/onMouseEnd实现:

  • 每一个标签监听onMouseDown事件

    1. 记录以后点击的标签(movingTagPath)
    2. 一些地位(originMousePos/originTagPos)
    3. 设置以后标签为选中状态
  • document监听mousemovemouseup事件

    1. mousemove处理函数中计算挪动的间隔,(解决边界值后)设置movingTagPos
    2. mouseup处理函数中重置movingTagPos/movingTagPath并移除document监听的事件
  • 标签父元素监听onMouseMove事件

    1. 解决拖动过程中标签地位更新逻辑
//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]);