首頁 > 軟體

自定義range sliders滾軸實現元素拖動方法

2022-08-17 14:01:49

1. 使用原生 range input

這篇文章介紹兩種建立 range slider 滾軸的方法。

老樣子,話不多說,先上菜。

const knob = document.getElementById('knob');
// 左邊的滑條
const leftSide = knob.previousElementSibling;
// 當前滑鼠位置
let x = 0;
let y = 0;
let leftWidth = 0;
// 處理 mousedown 事件
const mouseDownHandler = function (e) {
  // 獲取當前滑鼠位置
  x = e.clientX;
  y = e.clientY;
  leftWidth = leftSide.getBoundingClientRect().width;
  // 在 `document` 上新增事件
  document.addEventListener('mousemove', mouseMoveHandler);
  document.addEventListener('mouseup', mouseUpHandler);
};
knob.addEventListener('mousedown', mouseDownHandler);
const mouseMoveHandler = function (e) {
  // 滑鼠移動的距離
  const dx = e.clientX - x;
  const dy = e.clientY - y;
  const containerWidth = knob.parentNode.getBoundingClientRect().width;
  let newLeftWidth = ((leftWidth + dx) * 100) / containerWidth;
  // 限制範圍在 0 - 100
  newLeftWidth = Math.max(newLeftWidth, 0);
  newLeftWidth = Math.min(newLeftWidth, 100);
  leftSide.style.width = `${newLeftWidth}%`;
};
// 當鬆開滑鼠時觸發
const mouseUpHandler = function () {
  // ...
  // 移除事件
  document.removeEventListener('mousemove', mouseMoveHandler);
  document.removeEventListener('mouseup', mouseUpHandler);
};

input 元素本身支援設定 type 屬性為 range,渲染一個 slider 滾軸。

<input type="range" />

它的相容性也還不錯,支援所有現代瀏覽器以及 IE10 以上,但是它也有一些限制,比如:

  • 你不能自定義把手(中間藍色圓圈)
  • 並不是所有現代瀏覽器都支援垂直方向的 slider 滾軸

也就是說,它的自定義性不是很好,如果想要自定義 slider 滾軸的話,這種方式就無法滿足。

另外,相容性方面我們可以通過下面這段程式碼來進行檢測:

const isRangeInputSupported = function () {
  const ele = document.createElement('input');
  ele.setAttribute('type', 'range');
  // 如果當前瀏覽器不支援 `range` input
  // `type` 屬性會還原到 `text`
  return ele.type !== 'text';
};

利用瀏覽器本身的預設行為機制,來判斷當前瀏覽器是否支援 range input。

2. 建立自定義 range slider

一個 slider 滾軸由 3 部分組成,1 個把手和把手左右兩個的 2 個滑條。

我們先構造 HTML 結構,程式碼如下:

<div class="container">
  <div class="left"></div>
  <div class="knob" id="knob"></div>
  <div class="right"></div>
</div>

這 3 部分元素放置在同一行展示,右邊部分的滑條表示的的是 range input 的可用寬度。所以,我們可以使用如下 CSS 程式碼進行佈局。

.container {
  /* 內容水平居中 */
  display: flex;
  align-items: center;
  height: 1.5rem;
}
.right {
  /* 可用寬度 */
  flex: 1;
  height: 2px;
}

HTML 和 CSS 結構有了,我們接著來處理拖動行為。

監聽 knob 把手的 mousedown 事件,記錄當前滑鼠的位置。

const knob = document.getElementById('knob');
// 左邊的滑條
const leftSide = knob.previousElementSibling;
// 當前滑鼠位置
let x = 0;
let y = 0;
let leftWidth = 0;
// 處理 mousedown 事件
const mouseDownHandler = function (e) {
  // 獲取當前滑鼠位置
  x = e.clientX;
  y = e.clientY;
  leftWidth = leftSide.getBoundingClientRect().width;
  // 在 `document` 上新增事件
  document.addEventListener('mousemove', mouseMoveHandler);
  document.addEventListener('mouseup', mouseUpHandler);
};
knob.addEventListener('mousedown', mouseDownHandler);

上面的程式碼要注意,mousedown 事件監聽在 knob 元素上,而 mousemovemouseup 事件則是監聽在 document 元素上。

document 元素上的監聽回撥事件 mouseMoveHandlermouseUpHandler 請看下文。

計算左側滑條寬度

當 knob 把手移動時,通過當前滑鼠位置和記錄的滑鼠位置,我們可以知道滑鼠移動的距離,這段距離就是左側滑條的寬度。

const mouseMoveHandler = function (e) {
  // 滑鼠移動的距離
  const dx = e.clientX - x;
  const dy = e.clientY - y;
  const containerWidth = knob.parentNode.getBoundingClientRect().width;
  let newLeftWidth = ((leftWidth + dx) * 100) / containerWidth;
  // 限制範圍在 0 - 100
  newLeftWidth = Math.max(newLeftWidth, 0);
  newLeftWidth = Math.min(newLeftWidth, 100);
  leftSide.style.width = `${newLeftWidth}%`;
};

移除 document 元素上的監聽事件

當滑動行為結束,也就是鬆開滑鼠的時候,我們還需要移除掉 document 元素上的監聽事件,防止重複監聽導致的問題。

// 當鬆開滑鼠時觸發
const mouseUpHandler = function () {
  // ...
  // 移除事件
  document.removeEventListener('mousemove', mouseMoveHandler);
  document.removeEventListener('mouseup', mouseUpHandler);
};
<div style="display: flex; justify-content: center; padding: 4rem">
  <div style="width: 16rem" class="container">
    <div class="left"></div>
    <div class="knob" id="knob"></div>
    <div class="right"></div>
  </div>
</div>

以上就是自定義range sliders滾軸實現元素拖動方法的詳細內容,更多關於range sliders滾軸元素拖動的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com