1. 实现的效果如下图所示:
2. 思路
1. 使用定位在左侧菜单栏右侧写一个不可见div,鼠标经过鼠标指针样式变换
2. 监听事件:鼠标按下、抬起、移动,需要一个变量,来记录当前是按下还是抬起,初始为false,按下时为true,抬起时为false,如果是true的情况可以移动。
3.记录鼠标偏移值e.screenX,借此控制菜单栏宽度,使用min、maxwidth控制最小或最大宽度
4.性能优化,采用节流或防抖
3.代码
分为js和react两个版本,以供参考
3.1 js核心代码简单理解版:
<div class="menu-wrapper"> <div class="resize-bar"></div> </div> <div class="content"></div> <script> let resizing = false const menu = document.querySelector('.menu-wrapper') const resizeBar = document.querySelector('.resize-bar') // 监听: 当鼠标按下,变量设置为true表示已经按下 resizeBar.addEventListener('mousedown', () => { resizing = true }) // 监听:当鼠标移动,将鼠标的位置赋值给元素的宽度 window.addEventListener('mousemove', (e) => { if (resizing) { e.preventDefault() e.stopPropagation() const { screenX } = e menu.style.width = screenX + 'px' } }) // 监听:当鼠标抬起,变量设置为false表示已经抬起 window.addEventListener('mouseup', () => { resizing = false; }) </script>
3.2 实际应用-react版
结合flex左右布局,鼠标控制的是左侧 flex:0 0 200px 的宽度,以及设置最小和最大的宽度,使用节流方式优化性能
// 设置的不可见div <div className='resize-bar' style={{ width: "10px", height: "100%", minHeight: "4.6875rem", position: "absolute", top: "0", right: "0", cursor: "col-resize", zIndex: "999999999" }} ></div> // react代码部分: setTimeout(() => { let prevCursorOffset = -1 let resizing = false const menu: any = document.querySelector(".mouseDrag") const resizeBar: any = document.querySelector(".resize-bar") resizeBar.addEventListener("mousedown", () => { resizing = true }) window.addEventListener("mousemove", handleResizeMenu) window.addEventListener("mouseup", () => { resizing = false }) function handleResizeMenu(e) { if (!resizing) { return } const {screenX} = e // 加上这两行代码,避免移动鼠标时选择界面元素 e.preventDefault() e.stopPropagation() if (prevCursorOffset === -1) { prevCursorOffset = screenX // 鼠标偏移量大于50时执行一次大小调整 } else if (Math.abs(prevCursorOffset - screenX) >= 50) { menu.style.flex = `0 0 ${screenX}px` // 设置左侧宽度 menu.style.maxWidth = "500px" // 设置左侧最大宽度 prevCursorOffset = screenX } } }, 1500)
4. 使用flex实现左右两栏式经典布局
好处:使用flex布局可以使右侧内容区域自适应
4.1 图示:
4.2 代码实例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>flex-左右布局</title> <style> .wrap { margin: 0 auto; width: 80%; display: flex; } #left { flex: 0 0 200px; /* 左侧固定200px */ height: 500px; background: red; } #right { flex: 1; /* 随父级变化 */ height: 500px; background: burlywood; } </style> </head> <body> <div class="wrap"> <aside id="left"></aside> <section id="right">右侧</section> </div> </body> </html>