使用vue3實(shí)現(xiàn)簡(jiǎn)單的滑塊組件
滑塊組件主要是利用鼠標(biāo)事件,讓滑塊跟著鼠標(biāo)跟著x軸動(dòng),效果如下。
創(chuàng)建了一個(gè)名為 CustomSlider
的自定義滑塊組件。它接受 min
、max
和 step
作為 props,用于設(shè)置滑塊的取值范圍和步長(zhǎng)。使用 emits
屬性聲明了一個(gè)名為 update:modelValue
的自定義事件,用于向父組件發(fā)送滑塊值的更新。
name: 'CustomSlider', props: { min: { type: Number, default: 0 }, max: { type: Number, default: 100 }, step: { type: Number, default: 1 } }, emits: ['update:modelValue'],
在 setup
函數(shù)中,我們使用了 Vue 3 的組合式 API 來定義滑塊組件的邏輯。我們使用了 ref
來創(chuàng)建了 thumbPosition
和 isDragging
兩個(gè)響應(yīng)式變量。thumbPosition
用于控制滑塊的位置,isDragging
用于標(biāo)記是否正在拖動(dòng)滑塊。
通過計(jì)算屬性 trackWidth
,我們根據(jù)最小值和最大值計(jì)算出滑塊軌道的寬度,用于動(dòng)態(tài)設(shè)置樣式。
const thumbPosition = ref('0%'); const isDragging = ref(false); const trackWidth = computed(() => { const range = props.max - props.min; return `${(100 * range) / (props.max - props.min)}%`; });
在 startDrag
方法中,我們監(jiān)聽了滑塊的鼠標(biāo)按下事件,并在按下時(shí)開始拖動(dòng)操作。在 handleDrag
方法中,我們根據(jù)鼠標(biāo)位置計(jì)算出滑塊的值,并通過 emit
方法觸發(fā) update:modelValue
事件,將滑塊的值發(fā)送給父組件。
const startDrag = (event) => { isDragging.value = true; document.addEventListener('mousemove', handleDrag); document.addEventListener('mouseup', stopDrag); }; const handleDrag = (event) => { if (isDragging.value) { const sliderWidth = event.target.parentNode.offsetWidth; const offsetX = event.pageX - event.target.parentNode.offsetLeft; const percentage = (offsetX / sliderWidth) * 100; const value = (percentage * (props.max - props.min)) / 100 + props.min; const snappedValue = Math.round(value / props.step) * props.step; const clampedValue = Math.max(props.min, Math.min(props.max, snappedValue)); thumbPosition.value = `${((clampedValue - props.min) / (props.max - props.min)) * 100}%`; emit('update:modelValue', clampedValue); } }; const stopDrag = () => { isDragging.value = false; document.removeEventListener('mousemove', handleDrag); document.removeEventListener('mouseup', stopDrag); };
在 onMounted
和 onUnmounted
鉤子中,我們分別添加和移除了監(jiān)聽鼠標(biāo)抬起事件的事件處理函數(shù),以確保在組件銷毀時(shí)正確清理事件監(jiān)聽器。
onMounted(() => { document.addEventListener('mouseup', stopDrag); }); onUnmounted(() => { document.removeEventListener('mouseup', stopDrag); });
完整代碼如下:
<template> <div class="slider"> <div class="track" :style="{ width: trackWidth }"></div> <div class="thumb" :style="{ left: thumbPosition }" @mousedown="startDrag"></div> </div> </template> <script> import { ref, computed, onMounted, onUnmounted } from 'vue'; export default { name: 'CustomSlider', props: { min: { type: Number, default: 0 }, max: { type: Number, default: 100 }, step: { type: Number, default: 1 } }, emits: ['update:modelValue'], setup(props, { emit }) { const thumbPosition = ref('0%'); const isDragging = ref(false); const trackWidth = computed(() => { const range = props.max - props.min; return `${(100 * range) / (props.max - props.min)}%`; }); const startDrag = (event) => { isDragging.value = true; document.addEventListener('mousemove', handleDrag); document.addEventListener('mouseup', stopDrag); }; const handleDrag = (event) => { if (isDragging.value) { const sliderWidth = event.target.parentNode.offsetWidth; const offsetX = event.pageX - event.target.parentNode.offsetLeft; const percentage = (offsetX / sliderWidth) * 100; const value = (percentage * (props.max - props.min)) / 100 + props.min; const snappedValue = Math.round(value / props.step) * props.step; const clampedValue = Math.max(props.min, Math.min(props.max, snappedValue)); thumbPosition.value = `${((clampedValue - props.min) / (props.max - props.min)) * 100}%`; emit('update:modelValue', clampedValue); } }; const stopDrag = () => { isDragging.value = false; document.removeEventListener('mousemove', handleDrag); document.removeEventListener('mouseup', stopDrag); }; onMounted(() => { document.addEventListener('mouseup', stopDrag); }); onUnmounted(() => { document.removeEventListener('mouseup', stopDrag); }); return { thumbPosition, trackWidth, startDrag }; } }; </script> <style> .slider { position: relative; width: 100%; height: 10px; background-color: #ccc; } .track { position: absolute; top: 0; left: 0; height: 100%; background-color: #409eff; } .thumb { position: absolute; top: -5px; left: 0; width: 20px; height: 20px; border-radius: 50%; background-color: #409eff; cursor: pointer; } </style>
到此這篇關(guān)于使用vue3實(shí)現(xiàn)簡(jiǎn)單的滑塊組件的文章就介紹到這了,更多相關(guān)vue3實(shí)現(xiàn)滑塊組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue創(chuàng)建項(xiàng)目卡住不動(dòng),vue?create?project卡住不動(dòng)的解決
這篇文章主要介紹了vue創(chuàng)建項(xiàng)目卡住不動(dòng),vue?create?project卡住不動(dòng)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10一篇文章帶你吃透Vue生命周期(結(jié)合案例通俗易懂)
這篇文章主要給大家介紹了關(guān)于如何通過一篇文章帶你吃透Vue生命周期,文章通過結(jié)合案例更加的通俗易懂,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-02-02vue生命周期beforeDestroy和destroyed調(diào)用方式
這篇文章主要介紹了vue生命周期beforeDestroy和destroyed調(diào)用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06vue項(xiàng)目網(wǎng)頁自適應(yīng)等比例放大縮小實(shí)例代碼
等比例縮放可以在不同的分辨率下都能夠一屏展示,不會(huì)有滾動(dòng)條的問題,也不會(huì)有適配問題,下面這篇文章主要給大家介紹了關(guān)于vue項(xiàng)目網(wǎng)頁自適應(yīng)等比例放大縮小的相關(guān)資料,需要的朋友可以參考下2022-11-11proxy實(shí)現(xiàn)vue3數(shù)據(jù)雙向綁定原理
這篇文章主要介紹了proxy實(shí)現(xiàn)vue3數(shù)據(jù)雙向綁定原理,文章以介紹proxy的優(yōu)點(diǎn)開始展開全文內(nèi)容,圍繞proxy實(shí)現(xiàn)vue3數(shù)據(jù)雙向綁定的相關(guān)資料,,需要的朋友可以參考一下2021-12-12Vue v-for中的 input 或 select的值發(fā)生改變時(shí)觸發(fā)事件操作
這篇文章主要介紹了Vue v-for中的 input 或 select的值發(fā)生改變時(shí)觸發(fā)事件操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-08-08