使用Vue3實現(xiàn)簡單的鼠標跟隨效果
1. 創(chuàng)建組件基本結構
首先,創(chuàng)建一個 Vue3 組件,我們把它命名為 PageCursor.vue?;窘Y構如下:
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
const props = withDefaults(defineProps<{
hideCursorSelector?: string | string[]
}>(), {
hideCursorSelector: '.hide-page-cursor'
})
const cursor = ref<HTMLElement | null>(null)
const cursorType = ref('auto')
const cursorState = ref('')
onMounted(() => {})
onUnmounted(() => {})
</script>
<template>
<div
ref="cursor"
class="page-cursor"
:class="[cursorType, cursorState]"
></div>
</template>
<style lang="scss" scoped>
.page-cursor {
--cursor-size: 20px;
position: fixed;
z-index: 9999;
top: calc(-1 * var(--cursor-size) / 2);
left: calc(-1 * var(--cursor-size) / 2);
width: var(--cursor-size);
height: var(--cursor-size);
border-radius: 50%;
backdrop-filter: invert(100%);
pointer-events: none;
opacity: 0;
}
</style>
在組件中,我們定義了 props 對象、三個響應式對象和一個 page-cursor 樣式類
props 對象用于接收參數(shù)。使用 props 傳參可以在外部引用組件時控制組件的樣式或行為,這里我們只定義了一個 hideCursorSelector 參數(shù)用于設置隱藏光標這個行為。
三個響應式對象分別是:
cursor:跟隨鼠標運動的光標元素。cursorType:光標的類型。cursorState:光標的狀態(tài)。
page-cursor 樣式類:
--cursor-size:主要是設置光標的大小,后續(xù)有多個地方會用到,所以將其定義為 CSS 變量。top、left、width、height:基于--cursor-size變量進行位置和大小的設置。backdrop-filter:將其值設置為invert(100%)為光標后面區(qū)域添加反色效果。pointer-events:將其值設置為none來禁用光標的指針事件,使其不會影響頁面上其他元素的交互。
2. 添加鼠標響應事件
添加鼠標響應事件(移動、按下、彈起)并在組件掛載時注冊事件,在組件卸載時移除事件:
function onMousemove() {}
function onMousedown() {}
function onMouseup() {}
onMounted(() => {
document.addEventListener('mousemove', onMousemove)
document.addEventListener('mousedown', onMousedown)
document.addEventListener('mouseup', onMouseup)
})
onUnmounted(() => {
document.removeEventListener('mousemove', onMousemove)
document.removeEventListener('mousedown', onMousedown)
document.removeEventListener('mouseup', onMouseup)
})
3. 實現(xiàn)具體功能
在 onMousedown 和 onMouseup 中修改光標狀態(tài):
function onMousedown() {
cursorState.value = 'pressed'
}
function onMouseup() {
cursorState.value = ''
}
在 onMousemove 事件中獲取鼠標位置,并在 requestAnimationFrame 方法中進行更新位置:
let myReq: number = 0
function onMousemove(event: MouseEvent) {
if(!cursor.value) return
cancelAnimationFrame(myReq)
const { clientX, clientY } = event
const target = event.target as HTMLElement
myReq = requestAnimationFrame(() => {
const style = cursor.value!.style
style.transform = `translate3d(${clientX}px, ${clientY}px, 0)`
cursorType.value = getComputedStyle(target)?.cursor || 'auto'
const hideCursorSelectorList = Array.isArray(props.hideCursorSelector)
? props.hideCursorSelector
: [props.hideCursorSelector]
const hideCursor = hideCursorSelectorList.some(item => target.closest(item) !== null)
style.opacity = hideCursor ? '0' : '1'
style.transition = hideCursor ? '0.2s ease-out' : '0.125s ease-out'
})
}
在這段代碼中,首先使用 cancelAnimationFrame 方法關閉之前創(chuàng)建的動畫幀任務。然后獲取當前鼠標的坐標和指向的元素。利用 requestAnimationFrame 方法在下一幀渲染前進行樣式設置,以防止在同一幀內執(zhí)行多次樣式設置。并使用 getComputedStyle 方法獲取當前鼠標指向元素的 CSS 屬性,并從中獲取鼠標指針的類型。
最后,將 hideCursorSelector 格式化為 hideCursorSelectorList,通過檢查鼠標指向元素與 hideCursorSelectorList 匹配特定選擇器且離當前元素最近的祖先元素是否存在來判斷是否隱藏光標。
4. 光標的狀態(tài)設置
.page-cursor {
// 其他 page-cursor 樣式
// 鼠標光標類型為指針時
&.pointer {
--cursor-size: 40px;
// 指針類型并且按下時
&.pressed {
--cursor-size: 20px;
}
}
// 默認類型按下時
&.pressed {
--cursor-size: 10px;
}
}
你還可以在不同的鼠標事件中對 cursorState 和 cursorType 進行賦值,并對 page-cursor 樣式類進行更多的定義,來實現(xiàn)更多光標形態(tài)的展示。
5. 完整代碼
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
const props = withDefaults(defineProps<{
hideCursorSelector?: string | string[]
}>(), {
hideCursorSelector: '.hide-page-cursor'
})
const cursor = ref<HTMLElement | null>(null)
const cursorType = ref('auto')
const cursorState = ref('')
let myReq: number = 0
function onMousemove(event: MouseEvent) {
if(!cursor.value) return
cancelAnimationFrame(myReq)
const { clientX, clientY } = event
const target = event.target as HTMLElement
myReq = requestAnimationFrame(() => {
const style = cursor.value!.style
style.transform = `translate3d(${clientX}px, ${clientY}px, 0)`
cursorType.value = getComputedStyle(target)?.cursor || 'auto'
const hideCursorSelectorList = Array.isArray(props.hideCursorSelector)
? props.hideCursorSelector
: [props.hideCursorSelector]
const hideCursor = hideCursorSelectorList.some(item => target.closest(item) !== null)
style.opacity = hideCursor ? '0' : '1'
style.transition = hideCursor ? '0.2s ease-out' : '0.125s ease-out'
})
}
function onMousedown() {
cursorState.value = 'pressed'
}
function onMouseup() {
cursorState.value = ''
}
onMounted(() => {
globalThis.document.addEventListener('mousemove', onMousemove)
globalThis.document.addEventListener('mousedown', onMousedown)
globalThis.document.addEventListener('mouseup', onMouseup)
})
onUnmounted(() => {
globalThis.document.removeEventListener('mousemove', onMousemove)
globalThis.document.removeEventListener('mousedown', onMousedown)
globalThis.document.removeEventListener('mouseup', onMouseup)
})
</script>
<template>
<div
ref="cursor"
class="page-cursor"
:class="[cursorType, cursorState]"
></div>
</template>
<style lang="scss" scoped>
.page-cursor {
--cursor-size: 20px;
position: fixed;
z-index: 9999;
top: calc(-1 * var(--cursor-size) / 2);
left: calc(-1 * var(--cursor-size) / 2);
width: var(--cursor-size);
height: var(--cursor-size);
border-radius: 50%;
backdrop-filter: invert(100%);
pointer-events: none;
opacity: 0;
&.pointer {
--cursor-size: 40px;
&.pressed {
--cursor-size: 20px;
}
}
&.pressed {
--cursor-size: 10px;
}
}
</style>
6.效果圖

到此這篇關于使用Vue3實現(xiàn)簡單的鼠標跟隨效果的文章就介紹到這了,更多相關Vue3鼠標跟隨內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
vue-router3.x和vue-router4.x相互影響的問題分析
這篇文章主要介紹了vue-router3.x和vue-router4.x相互影響的問題分析,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-04-04
vue用addRoutes實現(xiàn)動態(tài)路由的示例
本篇文章主要介紹了vue用addRoutes實現(xiàn)動態(tài)路由的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-09-09
BuildAdmin elementPlus自定義表頭添加tooltip方法示例
這篇文章主要介紹了BuildAdmin elementPlus 自定義表頭,添加tooltip實現(xiàn)方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-09-09
利用Vite搭建Vue3+ElementUI-Plus項目的全過程
vue3如今已經成為默認版本了,相信大多數(shù)公司已經全面擁抱vue3了,下面這篇文章主要給大家介紹了關于利用Vite搭建Vue3+ElementUI-Plus項目的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-07-07

