首页 前端知识 使用react css实现一个轻量的可拖拽侧边栏布局

使用react css实现一个轻量的可拖拽侧边栏布局

2024-10-17 10:10:02 前端知识 前端哥 675 883 我要收藏

需求

实现一个左右布局,其中左侧边栏可以通过拖拽中间的分割线改变宽度。
在这里插入图片描述

原理

在位置确定方面

我们拖动的左右交接的那根线(图中浅蓝色那个竖线),并非左右块的边界,而是一个比较窄的div,我这里设置宽度是4px

如果,我们假设左侧边栏的宽度是X,那么有以下推论:

  • absolute布局下,左侧边栏的位置就可以设置为top:0,left:0,bottom:0,width:X
  • 右侧内容部分的位置就可以设为top:0,bottom:0,right:0,left:X
  • 拖拽条的位置是top:0,bottom:0,left:X-2,width:4px

所以,我们只需要一个React的状态变量X就可以确定所有的内容位置和大小。

在拖拽动作方面

  • 我们在拖拽条上点击鼠标左键
  • 然后进入拖拽状态(整个内容区域被mask遮盖)
  • 在拖拽状态下(鼠标左键没有松开),我们左右移动鼠标,通过e.pageX获取鼠标的位置,从而确定X的值。
  • 当鼠标左键抬起,退出拖拽状态,mask消失,拖拽过程结束。

这个过程涉及三个动作:

  • 拖拽条上的鼠标左键点击
  • mask上的鼠标拖拽
  • mask上的鼠标左键抬起

到此为止,我们的原理已经非常明白了,我们需要定义两个状态变量,一个是确定左侧宽度的X,另一个是表示进入拖拽状态的Flag。

代码

以下是完整代码:

index.js

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

.resizeable-layout {
  width: 100%;
  height: 100vh;
}

.left {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  background-color: antiquewhite;
}

.right {
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0;
  background-color: beige;
}

.slidebar {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 4px;
  cursor: col-resize;//鼠标箭头提示可拖拽
}

.dragging-mask {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.1);//拖拽过程中页面微微变灰
  cursor: col-resize;
}

App.js

import { useState } from 'react'
import './index.css'
export default function ResizeableLayout() {
  const [leftWidth, setLeftWidth] = useState(parseInt(localStorage.getItem('leftWidth')) || 150)
  const [dragging, setDragging] = useState(false)
  const slidebarColorOnDragging = 'lightblue'
  const slidebarColorDefault = 'rgba(0,0,0,0)'
  const [slidebarColor, setSlidebarColor] = useState(slidebarColorDefault)

  function handleLeftKeyDown(e) {
    if (e.button === 0) {//判断是鼠标左键按下
      setDragging(true)
      setSlidebarColor(slidebarColorOnDragging)
    }
  }
  function handleMouseMove(e) {
    if (dragging) {
      setLeftWidth(e.pageX)
    }
  }
  function handleMouseUp(e) {
    setDragging(false)
    setSlidebarColor(slidebarColorDefault)
    localStorage.setItem('leftWidth', leftWidth)
  }

  return (
    <div className="resizeable-layout">
      <div className="left" style={{ width: leftWidth }}>
        left
      </div>
      <div className="right" style={{ left: leftWidth }}>
        right
      </div>
      <div className='slidebar' style={{ left: leftWidth - 2, background: slidebarColor }} onMouseDown={(e) => handleLeftKeyDown(e)}></div>
      {dragging && <div className='dragging-mask' onMouseMove={(e) => handleMouseMove(e)} onMouseUp={(e) => handleMouseUp(e)} ></div>}
    </div>
  )
}
转载请注明出处或者链接地址:https://www.qianduange.cn//article/19080.html
标签
评论
发布的文章
大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!