使用resize属性实现元素拖拉改变宽度

1.背景

地图页面左侧全量树新需求,想要实现左侧树的拖拉效果,方便用户使用。

查阅资料发现使用js逻辑,通过监听鼠标按下、移动、抬起事件等进行处理可以实现,但是考虑到地图页面的性能已经吃不消了,于是不使用此方法实现。

之前看过相关css中的resize属性使用的文章,查看有关博客感觉可以实现元素的拖拉效果,于是使用resize属性进行功能实现。

2.小demo热身

参考了张鑫旭老师的纯CSS实现分栏宽度拉伸调整demo。

https://www.zhangxinxu.com/study/201903/css-idea/behavior-stretch.php?aside=0

自己动手试了一下,发现了一些小问题,示例如下。

<!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>Document</title>
  <style>
    html, body {
      height: 100%;
    }
    .box {
      display: flex;
      overflow: hidden;
      height: 100%;
    }
    .left, .right {
      height: 100%;
      position: relative;
    }
    .left-reisze {
      width: 200px;
      height: inherit;
      resize: horizontal;
      overflow: scroll;
      cursor: col-resize;
      opacity: 0;
    }
    .resize-save {
      position: absolute;
      top: 0; right: 8px; bottom: 0; left: 0;
      padding: 16px;
      overflow-x: hidden;
    }
    .resize-line {
      position: absolute;
      width: 4px;
      right: 0; top: 0; bottom: 0;
      border-right: 2px solid #eee;
      border-left: 1px solid #bbb;
      pointer-events: none;
    }
    .left-reisze:hover ~ .resize-line,
    .left-reisze:active ~ .resize-line {
      border-left: 1px dashed skyblue;
    }
    .left-reisze::-webkit-scrollbar {
      width: 200px;
      height: inherit;
    }
  </style>
</head>
<body>
  <div class="box">
    <div class="left">
      <div class="left-reisze"></div>
      <div class="resize-line"></div>
      <div class="resize-save">Left</div>
    </div>
    <div class="right">Right</div>
  </div>
</body>
</html>

发现当父容器leftheight设置为100%时,webkit-scrollbar的高度设置为inherit时不生效,感觉高度变为0了。只有父容器left设置为固定高度时,webkit-scrollbar的高度设置为inherit时才能正常继承。

这里有个简单的解决方法,不考虑大屏展示时可以给webkit-scrollbar设置个固定高度2000px,考虑大屏展示再设置大一些。

还有个解决方法,要结合js使用,强行塞个高度。

<!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>Document</title>
  <style>
    html, body {
      height: 100%;
    }
    .box {
      display: flex;
      overflow: hidden;
      height: 100%;
    }
    .left, .right {
      height: 100%;
      position: relative;
    }
    .left-reisze {
      width: 200px;
      // max-width: 750px; 这里可以设置最大、最小拖拉宽度
      height: inherit;
      resize: horizontal;
      overflow: scroll;
      cursor: col-resize;
      opacity: 0;
    }
    .resize-save {
      position: absolute;
      top: 0; right: 4px; bottom: 0; left: 0;
      padding: 16px;
      overflow-x: hidden;
    }
    .resize-line {
      position: absolute;
      width: 4px;
      right: 0; top: 0; bottom: 0;
      border-right: 2px solid #eee;
      border-left: 1px solid #bbb;
      pointer-events: none;
    }
    .left-reisze:hover ~ .resize-line,
    .left-reisze:active ~ .resize-line {
      border-left: 1px dashed skyblue;
    }
    .left-reisze::-webkit-scrollbar {
      width: 200px;
      height: inherit;
    }
  </style>
</head>
<body>
  <div class="box">
    <div class="left">
      <div class="left-reisze"></div>
      <div class="resize-line"></div>
      <div class="resize-save">Left</div>
    </div>
    <div class="right">Right</div>
  </div>
  <script>
    const node = document.querySelector('.left')
    node.setAttribute('style',`height:${node.clientHeight}px`)
  </script>
</body>
</html>

3.项目上使用

项目上使用的布局与上面的demo类似,只是在使用js处理webkit-scrollbar的高度时监听了浏览器的reisze事件。

mounted() {
  this.updateHeight();
  window.onresize = () => {
    this.$nextTick(() => {
      this.updateHeight();
    });
  };
},
 
updateHeight() {
  const node = document.querySelector('.rel-tree');
  node.setAttribute('style', '');
  this.$nextTick(() => {
    node.setAttribute('style', `height:${node.clientHeight}px`);
  });
},

4.注意点

1.resize-save盒子中内容超出left盒子宽度时,会被遮盖

.test {
      width: 400px;
      height: 400px;
      background-color: pink;
}

<div class="box">
  <div class="left">
    <div class="left-reisze"></div>
    <div class="resize-line"></div>
    <div class="resize-save">
      Left
      <div class="test"></div>
    </div>
  </div>
  <div class="right">Right</div>
</div>

2.绝对定位问题

resize-save绝对定位盒子中的元素,使用绝对定位时,当超出left盒子显示区域时发现会被遮挡不可见,怎么改变z-index都无法全部显示,类似上面的第一种情况,有点不知道原因,这里的解决方式是改用了fixed固定定位。

3.滚动条无限滚动问题

就是横向滚动条进行滚动时,滚的没完没了了,分明内容滚到底了,但是还能横向滚动,此时页面上展示的全是空白内容。

这是一个无法理解的问题,使用中没碰到正好,碰到时可以使用一个骚操作解决。我的理解是resize-save盒子的right为4px,给有滚动条的元素设置宽度是不直接设置100%,而是设置为width:calc(100% + 4px);,让此滚动元素与left盒子宽度相同或者大于left盒子宽度,就解决了,不知道问题的所在。