自定義range?sliders滑塊實(shí)現(xiàn)元素拖動(dòng)方法
1. 使用原生 range input
這篇文章介紹兩種創(chuàng)建 range slider 滑塊的方法。
老樣子,話不多說(shuō),先上菜。
const knob = document.getElementById('knob'); // 左邊的滑條 const leftSide = knob.previousElementSibling; // 當(dāng)前鼠標(biāo)位置 let x = 0; let y = 0; let leftWidth = 0; // 處理 mousedown 事件 const mouseDownHandler = function (e) { // 獲取當(dāng)前鼠標(biāo)位置 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) { // 鼠標(biāo)移動(dòng)的距離 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}%`; }; // 當(dāng)松開(kāi)鼠標(biāo)時(shí)觸發(fā) const mouseUpHandler = function () { // ... // 移除事件 document.removeEventListener('mousemove', mouseMoveHandler); document.removeEventListener('mouseup', mouseUpHandler); };
input 元素本身支持設(shè)置 type 屬性為 range,渲染一個(gè) slider 滑塊。
<input type="range" />
它的兼容性也還不錯(cuò),支持所有現(xiàn)代瀏覽器以及 IE10 以上,但是它也有一些限制,比如:
- 你不能自定義把手(中間藍(lán)色圓圈)
- 并不是所有現(xiàn)代瀏覽器都支持垂直方向的 slider 滑塊
也就是說(shuō),它的自定義性不是很好,如果想要自定義 slider 滑塊的話,這種方式就無(wú)法滿足。
另外,兼容性方面我們可以通過(guò)下面這段代碼來(lái)進(jìn)行檢測(cè):
const isRangeInputSupported = function () { const ele = document.createElement('input'); ele.setAttribute('type', 'range'); // 如果當(dāng)前瀏覽器不支持 `range` input // `type` 屬性會(huì)還原到 `text` return ele.type !== 'text'; };
利用瀏覽器本身的默認(rèn)行為機(jī)制,來(lái)判斷當(dāng)前瀏覽器是否支持 range input。
2. 創(chuàng)建自定義 range slider
一個(gè) slider 滑塊由 3 部分組成,1 個(gè)把手和把手左右兩個(gè)的 2 個(gè)滑條。
我們先構(gòu)造 HTML 結(jié)構(gòu),代碼如下:
<div class="container"> <div class="left"></div> <div class="knob" id="knob"></div> <div class="right"></div> </div>
這 3 部分元素放置在同一行展示,右邊部分的滑條表示的的是 range input 的可用寬度。所以,我們可以使用如下 CSS 代碼進(jìn)行布局。
.container { /* 內(nèi)容水平居中 */ display: flex; align-items: center; height: 1.5rem; } .right { /* 可用寬度 */ flex: 1; height: 2px; }
HTML 和 CSS 結(jié)構(gòu)有了,我們接著來(lái)處理拖動(dòng)行為。
監(jiān)聽(tīng) knob 把手的 mousedown 事件,記錄當(dāng)前鼠標(biāo)的位置。
const knob = document.getElementById('knob'); // 左邊的滑條 const leftSide = knob.previousElementSibling; // 當(dāng)前鼠標(biāo)位置 let x = 0; let y = 0; let leftWidth = 0; // 處理 mousedown 事件 const mouseDownHandler = function (e) { // 獲取當(dāng)前鼠標(biāo)位置 x = e.clientX; y = e.clientY; leftWidth = leftSide.getBoundingClientRect().width; // 在 `document` 上添加事件 document.addEventListener('mousemove', mouseMoveHandler); document.addEventListener('mouseup', mouseUpHandler); }; knob.addEventListener('mousedown', mouseDownHandler);
上面的代碼要注意,mousedown
事件監(jiān)聽(tīng)在 knob 元素上,而 mousemove
和 mouseup
事件則是監(jiān)聽(tīng)在 document 元素上。
document 元素上的監(jiān)聽(tīng)回調(diào)事件 mouseMoveHandler
和 mouseUpHandler
請(qǐng)看下文。
計(jì)算左側(cè)滑條寬度
當(dāng) knob 把手移動(dòng)時(shí),通過(guò)當(dāng)前鼠標(biāo)位置和記錄的鼠標(biāo)位置,我們可以知道鼠標(biāo)移動(dòng)的距離,這段距離就是左側(cè)滑條的寬度。
const mouseMoveHandler = function (e) { // 鼠標(biāo)移動(dòng)的距離 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 元素上的監(jiān)聽(tīng)事件
當(dāng)滑動(dòng)行為結(jié)束,也就是松開(kāi)鼠標(biāo)的時(shí)候,我們還需要移除掉 document 元素上的監(jiān)聽(tīng)事件,防止重復(fù)監(jiān)聽(tīng)導(dǎo)致的問(wèn)題。
// 當(dāng)松開(kāi)鼠標(biāo)時(shí)觸發(fā) 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滑塊實(shí)現(xiàn)元素拖動(dòng)方法的詳細(xì)內(nèi)容,更多關(guān)于range sliders滑塊元素拖動(dòng)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
javascript數(shù)據(jù)類型之原始類型詳解
這篇文章主要為大家介紹了javascript數(shù)據(jù)類型之原始類型詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06Proxy Facade設(shè)計(jì)模式簡(jiǎn)化系統(tǒng)訪問(wèn)的強(qiáng)大工具原理詳解
這篇文章主要為大家介紹了 Proxy Facade設(shè)計(jì)模式簡(jiǎn)化系統(tǒng)訪問(wèn)的強(qiáng)大工具原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10JavaScript?設(shè)計(jì)模式之洋蔥模型原理及實(shí)踐應(yīng)用
這篇文章主要介紹了JavaScript?設(shè)計(jì)模式之洋蔥模型原理及實(shí)踐應(yīng)用,主要針對(duì)項(xiàng)目中遇到的問(wèn)題,引申到koa-compose原理解析。通過(guò)學(xué)習(xí)洋蔥模式來(lái)解決我們實(shí)際項(xiàng)目中的問(wèn)題2022-09-09微信小程序 利用css實(shí)現(xiàn)遮罩效果實(shí)例詳解
這篇文章主要介紹了微信小程序 利用css實(shí)現(xiàn)遮罩效果實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-01-01微信小程序 藍(lán)牙的實(shí)現(xiàn)實(shí)例代碼
這篇文章主要介紹了微信小程序 藍(lán)牙的實(shí)現(xiàn)實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2017-06-06