拖拽滾動檢視(一)

房東家的貓 發表於 2020-10-26

拖拽滾動檢視(一)

滑鼠拖拽

事件

container.addEventListener("touchstart", dragStart, false);// 進入
container.addEventListener("touchend", dragEnd, false); // 離開
container.addEventListener("touchmove", drag, false); // 移動

container.addEventListener("mousedown", dragStart, false); // 進入
container.addEventListener("mouseup", dragEnd, false); // 離開
container.addEventListener("mousemove", drag, false);// 移動

Element.getBoundingClientRect()

返回元素的大小及其相對視口的位置,以css設定寬高作為衡量準備

offset(只讀)

Element.offsetWidth css寬度,包括border,padding,scrollbar(水平滾動條),width

Element.offsetHeight css 高度,包括 border,padding,scrollbar(垂直滾動條),height

Element.offsetLeft 左邊的偏移值

Element.offsetTop 距離頂部的偏移值

Element.offsetParent

  • 如果父級有定位,返回帶有定位的父級dom
  • 如果父級沒有定位,返回body

client(只讀)

可視區域

MouseEvent.clientWidth 元素內部寬度(包括padding,不包括scrollBar,border,margin)

MouseEvent.clientHeight 元素內部高度(包括padding,不包括scrollBar,border,margin)

MouseEvent.clientX 滑鼠距離可視區域左邊的距離

MouseEvent.clientY ... 上邊的距離

Element.clientTop dom 上邊框(border)的寬度

Element.clientLeft dom 左邊框(border)的寬度

scroll

距離: 可視區域+滾動隱藏的部分

Element.scrollTop 讀取設定, 距離頂部的距離

Element.scrollLeft 讀取設定, 距離元素left的距離

拖拽效果

程式碼對映結構

 // 按下
  box.onmousedown = function (event) {
    console.log(1);
    // 移動
    box.onmousemove=function () {
      console.log(2);
    }
    // 抬起
    box.onmouseup=function () {
      console.log(3);
    }
  }

邏輯

  • 滑鼠按下,獲取滑鼠點選時獲取相對位置
  • 滑鼠移動,元素的位置=滑鼠的位置-剛剛的差值
  • 滑鼠放下,給滑鼠移動和滑鼠放下設定為null
  <style>
    .box {
      width: 100%;
      height: 80vh;
      /*display: flex;*/
      /*justify-content: center;*/
      /*align-items: center;*/
      position: relative;
      border: 2px solid red;
    }

    .aaa {
      position: absolute;
      width: 50px;
      height: 50px;
      background-color: rgb(245, 230, 99);
      border: 10px solid rgba(136, 136, 136, .5);
      border-radius: 50%;
    }

    .aaa:hover {
      cursor: pointer;
      border-width: 20px;
    }

    .aaa:active {
      background-color: rgba(168, 218, 220, 1.00);
    }
  </style>

<div class="box" id="box">
  <div id="ccc" class="aaa"></div>
</div>

<script>
  /* mousedown 滑鼠進入
  *  mousemove 滑鼠移動
  *  mouseup 滑鼠離開
  * */
  let ccc = document.querySelector("#ccc");
  let box = document.querySelector("#box");

  // 按下
  ccc.onmousedown = function (event) {

    let x = event.clientX - this.offsetLeft
    let y = event.clientY - this.offsetTop
    // 移動
    document.onmousemove = function (e) {
      ccc.style.left = e.pageX - x + 'px';
      ccc.style.top = e.pageY - y + 'px';
    }
    // 抬起
    document.onmouseup = function () {
      document.onmousemove = null;
      document.onmouseup = null;
    }
  }
</script>

拖拽範圍限制

 /* mousedown 滑鼠進入
  *  mousemove 滑鼠移動
  *  mouseup 滑鼠離開
  * */
  let box = document.querySelector("#box");
  let ccc = document.querySelector("#ccc");

  ccc.onmousedown = function (event) {
    // 子盒子
    let w = ccc.getBoundingClientRect().width / 2;
    let h = ccc.getBoundingClientRect().height / 2;
    // 大盒子-小盒子
    let width = box.getBoundingClientRect().width - w;
    let height = box.getBoundingClientRect().height - h;
    // 按下的位置距離左側的差值
    let x = event.clientX - this.offsetLeft
    let y = event.clientY - this.offsetTop
    // 移動
    document.onmousemove = function (e) {
      // 移動的座標-左側的座標=子盒子的座標
      let x1 = e.pageX - x
      let y1 = e.pageY - y;
      if (-w < x1 && x1 < width) {
        ccc.style.left = x1 + 'px';
      }
      if (-h < y1 && y1 < height) {
        ccc.style.top = y1 + 'px';
      }
    }
    // 抬起
    document.onmouseup = function () {
      document.onmousemove = null;
      document.onmouseup = null;
    }
  }

我們發現出現滾動條的一些問題

發現了會出現,滾動條的bug, 那肯定是有些東西被隱藏點了

滾動條隱藏的解決方案

document.documentElement.scrollTop
window.pageYOffset

如果是對應的子盒子出現了滾動條,可以在對應的新增

關鍵程式碼修改

  // 按下的位置距離左側的差值
    let x =(window.pageXOffset+ event.clientX) - this.offsetLeft
    let y = (window.pageYOffset+event.clientY) - this.offsetTop

思考如何讓檢視跟著拖拽移動呢

首先理解一個比較基礎的問題

滾動的長度 scrollTop

scrollHeight=scrollTop+clientHeight

拖拽滾動檢視(一)

同理

scrollWidth=scrollLeft+clientWidth

科普: 滾動的相對距離

scrollBy(x,y) x和y指定滾動的相對量

案例

拖拽滾動檢視(一)

整體邏輯就一句話

移動的距離/總移動的距離=滑鼠移動的距離/總長度

具體點就是

滾動條移動的距離/滾動條移動的總距離=滑鼠移動的比較/總盒子可以移動的距離

上程式碼

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    .box-over {
      width: 60%;
      height: 60vh;
      overflow: auto;
    }

    .box {
      width: 140%;
      height: 150vh;
      margin: 200px auto;
      position: relative;
      border: 2px solid red;
    }

    .aaa {
      position: absolute;
      width: 50px;
      height: 50px;
      background-color: rgb(245, 230, 99);
      border: 10px solid rgba(136, 136, 136, .5);
      border-radius: 50%;
    }

    .aaa:hover {
      cursor: pointer;
      border-width: 20px;
    }

    .aaa:active {
      background-color: rgba(168, 218, 220, 1.00);
    }
  </style>
</head>
<body>
<div class="box-over">
  <div class="box" id="box">
    <div id="ccc" class="aaa"></div>
  </div>
</div>


<script>
  /* mousedown 滑鼠進入
  *  mousemove 滑鼠移動
  *  mouseup 滑鼠離開
  * */
  let box = document.querySelector("#box");
  let ccc = document.querySelector("#ccc");
  let over = document.querySelector('.box-over');
  ccc.onmousedown = function (event) {
    //計算大盒子內部的寬高
    let overW = box.getBoundingClientRect().width;
    let overH = box.getBoundingClientRect().height;
    //大盒子滾動條移動的距離
    let overs = {
      x: over.scrollWidth - over.clientWidth,
      y: over.scrollHeight - over.clientHeight,
    }
    // 子盒子
    let w = ccc.getBoundingClientRect().width / 2;
    let h = ccc.getBoundingClientRect().height / 2;
    // 大盒子-小盒子
    let width = box.getBoundingClientRect().width - w;
    let height = box.getBoundingClientRect().height - h;
    // 按下的位置距離左側的差值
    let x = (window.pageXOffset + event.clientX) - this.offsetLeft
    let y = (window.pageYOffset + event.clientY) - this.offsetTop
    // 移動
    document.onmousemove = function (e) {
      // 移動的座標-左側的座標=子盒子的座標
      let x1 = e.pageX - x
      let y1 = e.pageY - y;

      if (-w < x1 && x1 < width) {
        ccc.style.left = x1 + 'px';
      }
      if (-h < y1 && y1 < height) {
        ccc.style.top = y1 + 'px';
      }
      // 移動的距離/總距離=滑鼠移動的距離/總長度
      // 滾動條移動的距離/滾動條移動的總距離=滑鼠移動的比較/總盒子可以移動的距離
      over.scrollLeft = x1 / overW * overs.x
      over.scrollTop = y1 / overH * overs.y
    }
    // 抬起
    document.onmouseup = function () {
      document.onmousemove = null;
      document.onmouseup = null;
    }
  }
</script>
</body>
</html>