🎯 項目目標:
當鼠標在頁面移動時,小圓點會跟隨鼠標移動的位置,帶有平滑動畫。
🧠 實現思路:
-
HTML:
-
頁面內放一個
div
作為圓點。
-
-
CSS:
-
圓點使用絕對定位,初始在屏幕角落。
-
添加
transition
,讓位置平滑過渡(非瞬移)。 -
設置寬高、顏色(或圖片樣式)。
-
-
JavaScript:
-
監聽
mousemove
事件。 -
在事件中獲取鼠標
clientX/clientY
。 -
設置圓點的位置為鼠標位置附近。
-
?HTML 部分結構:
<div class="dot"></div>
實踐代碼如下::
初版JS(一個圓點的效果) :
const dot = document.getElementsByClassName('dot')document.addEventListener('mousemove', (event) => {console.log(event.clientX);const x = event.clientXconst y = event.clientYdot[0].style.top = ${y - 12.5}pxdot[0].style.left = ${x -12.5}px
})
CSS:
.dot {position: absolute;top: 0;left: 0;transition: all .2s ease;width: 25px;height: 25px;border-radius: 50%;background: yellowgreen;
};
?進階:添加拖尾效果(多個小點形成“尾巴”)
JS(多個圓點形成一個小尾巴的效果):
const dots = document.querySelectorAll('.dot')
let positions = Array.from({ length: dots.length }, () => ({ x: 0, y: 0 }));document.addEventListener('mousemove', (event) => {const { clientX: x, clientY: y } = event// 把當前位置放在隊列前面positions.unshift({ x, y })positions.length = dots.length// 每個圓點移動到對應的位置dots.forEach((dot, i) => {dot.style.left = positions[i].x + 'px'dot.style.top = positions[i].y + 'px'dot.style.opacity = 1 - i * 0.1dot.style.transform = `scale(${1 - i * 0.05})`})
})
CSS:
.dot {position: absolute;top: 0;left: 0;width: 25px;height: 25px;border-radius: 50%;background: yellowgreen;pointer-events: none;transition: top 0.2s, left 0.2s;
}
頁面效果展示:
?額外知識記錄:?
??關于多個圓點形成小尾巴的實現思路
1. 每次鼠標移動時:記錄當前位置。
-
用
positions.unshift({ x, y })
把當前坐標放進數組開頭,代表“最新”的位置。
2. 遍歷每個圓點,讓它去“追趕”對應的歷史鼠標位置。
-
第一個圓點移動到最新的位置,
-
第二個圓點移動到稍早前的位置,
-
依此類推,制造出延遲感的拖尾效果。
??關于為什么要給圓點加
pointer-events: none;
作用:讓這個元素不響應鼠標事件。?
你設置了 .dot
是鼠標指針跟隨的小圓點,如果不給它加 pointer-events: none
,你鼠標碰到它時就會“碰撞”上它(即便你看不出來),這樣就會阻礙 mousemove
的監聽。
🔹1.為什么不加上 pointer-events: none
會阻礙 mousemove
的監聽?
鼠標一旦停在 .dot
元素上:
- 瀏覽器會把
mousemove
事件發送給.dot
元素本身; - 如果你并沒有給
.dot
元素綁定mousemove
,事件就“斷了”, document
上的回調不再觸發,拖尾停止更新,看起來就像“卡住”。
總結
雖然你現在的代碼運行良好,肉眼可能看不出有什么卡頓,但養成加上
pointer-events: none
的習慣是更穩妥的。
??關于
const positions = Array.from({ length: dots.length }, () => ({ x: 0, y: 0 }))
🔹1. dots.length
是多少?
dots
是多個拖尾小圓點的 DOM 元素集合,例如:
const dots = document.querySelectorAll('.dot');
所以 dots.length
表示你想要多少個“尾巴”。
🔹2. Array.from({ length: dots.length }, ...)
是什么?
這是 Array.from
的一個常見用法,語法是:
Array.from({ length: N }, (value, index) => ...)
意思是:創建一個長度為 N 的數組,并用后面的函數生成每一項。
🔹3. 為什么要寫成 { length: dots.length }
?
因為 Array.from
的第一個參數可以是一個“類數組對象”(只要有 .length
屬性就行),比如:
Array.from({ length: 3 }) → [undefined, undefined, undefined]
🔹4. 回調函數 () => ({ x: 0, y: 0 })
是干嘛的?
這個函數的作用是:為數組中的每一項都返回一個初始坐標對象 { x: 0, y: 0 }
。
也就是說:
Array.from({ length: 3 }, () => ({ x: 0, y: 0 }));
// 結果是:
[{ x: 0, y: 0 },{ x: 0, y: 0 },{ x: 0, y: 0 }
]
🔹5. 為什么這么寫有必要?
這個 positions
數組的作用是:
記錄每一個尾巴圓點當前的位置。后續我們會用它來移動 .dot
的位置,實現拖尾軌跡。如果你有 10 個小圓點,就需要一個 10 項的數組,每一項都記錄這個圓點的位置。
?總結
這行代碼的含義就是:
“為每個
.dot
小圓點初始化一個位置對象 { x: 0, y: 0 },構成一個統一的positions
數組,用于后續跟隨鼠標拖尾。”
???關于
dot.style.opacity = 1 - i * 0.1;dot.style.transform = `scale(${1 - i * 0.05})`
這是給拖尾點添加視覺漸變和縮放的效果:
-
opacity = 1 - i * 0.1
-
第 0 個點透明度是
1
(完全不透明) -
第 1 個點是
0.9
-
第 2 個點是
0.8
... -
后面的點越來越透明
-
-
scale = 1 - i * 0.05
-
第 0 個點大小是
1
(原始大小) -
第 1 個點是
0.95
-
第 2 個點是
0.90
... -
后面的點越來越小
-
?總結
就是:“實現前面圓點大且亮,后面越來越小、越來越淡的尾巴效果。”