• [js] 实现侧边菜单可用鼠标拖动调整大小的功能


    element-ui 提供了一个 nav-menu 组件,默认情况下该组件没有拖动调整大小的功能。下面通过代码为 nav-menu 添加这个功能。

    样式问题

    鼠标悬于 nav-menu 上时,鼠标指针默认为 pointer,为了更好的指示调整能够调整菜单大小的功能,可以设置鼠标样式为 cursor: col-resize。当然显示为列调整大小的鼠标指针不能为一整个菜单,我这里的实现方案时给菜单添加一个不可见的 div,然后鼠标悬于这个 div 上时,才显示col-resize指针。

    DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Documenttitle>
      <style>
        body {
          margin: 0;
          position: relative;
          height: 100vh;
        }
    
        .menu-wrapper {
          position: absolute;
          left: 0;
          top: 0;
          height: 100%;
          width: 300px;
          background-color: #ccc;
        }
    
        .resize-bar {
          position: absolute;
          top: 0;
          right: 0px;
          width: 10px;
          height: 100%;
          cursor: col-resize;
          background-color: orange;
        }
    
        .content {
          margin-left: 300px;
          height: 100%;
          background-color: #999;
        }
      style>
    head>
    
    <body>
      <div class="menu-wrapper">
        <div class="resize-bar">div>
      div>
      <div class="content">div>
    body>
    
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    监听事件

    用户按下鼠标并移动鼠标指针,会触发 mousedownmousemove 事件,松开鼠标会触发 mouseup 事件,于是拖动的时机和顺序是:

    • mousedown -> 拖动 flag true
    • mousemove -> 检查拖动 flag 是否为 true,如果是执行拖动逻辑
    • mouseup -> 设置拖动 flag 为 false,并且可以取消事件监听等方法

    resize-bar 添加 mousedown 监听,因为只有在这个元素上按下鼠标才表示要调整菜单大小

    window 添加 mousemove 监听,能够避免移动鼠标时,元素宽度没更上鼠标指针而导致的移动中断

    同理给 window 添加 mouseup 监听。

    let resizing = false
    resizeBarElement.addEventListener('mousedown', () => {
    	resizing = true
    })
    
    window.addEventListener('mousemove', handleResizeMenu) // 见下文
    window.addEventListener('mouseup', () => {
    	resizing = false
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    大小控制

    实际上控制 menu 的大小只需依赖鼠标的偏移值,在 mousemove 的回调中,获取 e.screenX 就能得知当前鼠标的位置,把菜单的大小设置为鼠标的位置即可。

    function handleResizeMenu(e) {
    	if(!resizing) {
    		return ;
    	}
    	
    	const { screenX } = e
    	
    	// 加上这两行代码,避免移动鼠标时选择界面元素
    	e.preventDefault()
    	e.stopPropagation()
    
    	menu.style.width = screenX + 'px'
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    全部代码

    DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Documenttitle>
      <style>
        body {
          margin: 0;
          position: relative;
          height: 100vh;
        }
    
        .menu-wrapper {
          position: absolute;
          left: 0;
          top: 0;
          height: 100%;
          width: 300px;
          background-color: #ccc;
        }
    
        .resize-bar {
          position: absolute;
          top: 0;
          right: 0px;
          width: 10px;
          height: 100%;
          cursor: col-resize;
          background-color: orange;
        }
    
        .content {
          margin-left: 300px;
          height: 100%;
          background-color: #999;
        }
      style>
    head>
    
    <body>
      <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')
    
        resizeBar.addEventListener('mousedown', () => {
          resizing = true
        })
    
        window.addEventListener('mousemove', (e) => {
          if (resizing) {
            e.preventDefault()
            e.stopPropagation()
            const { screenX } = e
            menu.style.width = screenX + 'px'
          }
        })
    
        window.addEventListener('mouseup', () => {
          resizing = false;
        })
      script>
    body>
    
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    这里并没有动态调整 content 的 margin-left,感兴趣的同学可以加上。

    优化

    上面的代码没有限制鼠标移动的监听频率,会有性能浪费。我们可以在 mousemove 监听中计算鼠标的偏移量,如果偏移量大于指定值才调整大小。具体的实现思路是初始化一个 prevCursorOffset = -1,然后在监听代码中判断:

    let prevCursorOffset = -1
    window.addEventListener('mousemove', (e) => {
      if (resizing) {
       	e.preventDefault()
        e.stopPropagation()
        const { screenX } = e
        
      	if(prevCursorOffset === -1) {
    		prevCursorOffset = screenX
    	// 鼠标偏移量大于十时执行一次大小调整
    	} else if (Math.abs(prevCursorOffset - screenX) >= 10) {
        	menu.style.width = screenX + 'px'
        	prevCursorOffset = screenX
        }
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  • 相关阅读:
    【wireshark】如何获取一个设备的IP地址
    装备控制类嵌入式软件开发知识
    数论练习题
    C++设计模式
    c++ 信奥编程 1129:统计数字字符个数
    【毕业设计】基于stm32的车牌识别 - 单片机 嵌入式 物联网 机器视觉
    C语言基础知识
    【编码问题】使用 http 请求,中文乱码问题
    内存泄露详细介绍
    在线配置生成动态排序柱状图工具上线
  • 原文地址:https://blog.csdn.net/qq_39559879/article/details/127426078