Three.js鼠标悬停高亮球体功能异常:无法切换及恢复颜色
Let's get that hover highlight working properly! I’ve gone through your code and found three main issues causing the stuck state and unresponsive raycasting:
1. Local Variable Shadowing Breaks State Persistence
In your render method, you’re creating local variables (highlighted, intersectHighlighted) that shadow the reactive data properties. When you update these local variables, you’re not actually modifying the component’s state—so the next render cycle will just use the old values again.
Fix: Remove the local variable declarations and directly work with this.highlighted (you don’t even need to store intersectHighlighted in data, since it’s recalculated every frame).
2. Incorrect Condition in the Else Block
Your else condition else if (intersectHighlighted !== this.spheres.object) doesn’t make sense—intersectHighlighted is an array of raycast hits, and this.spheres is your array of sphere objects. They’ll never match, so the else block never triggers correctly.
Fix: Replace it with a simple check for intersectHighlighted.length === 0—this means no spheres are under the mouse, so we should reset the highlight.
3. Wrong Event Listener for Mouse Tracking
You’re using mouseover, which only fires once when the mouse enters the element. To track mouse movement across the scene, you need mousemove instead. You also duplicated the mouseover listener, which is unnecessary.
Fix: Update the event listener to use mousemove, and remove the duplicate binding.
Modified Code Snippet
Here’s the fixed version of your key methods:
init() { // ... (keep your existing setup code) // Replace mouseover with mousemove, remove duplicate listener map.addEventListener('mousemove', this.mouseOverScene, false); }, mouseOverScene (event) { event.preventDefault(); let rect = event.target.getBoundingClientRect(); let x = event.clientX - rect.left; let y = event.clientY - rect.top; this.mouse.x = (x / this.mapWidth) * 2 - 1; this.mouse.y = -(y / this.mapHeight) * 2 + 1; // No need to call setFromCamera here—we'll do it in render }, render() { // Calculate raycast hits every frame this.rayCaster.setFromCamera(this.mouse, this.camera); const intersects = this.rayCaster.intersectObjects(this.spheres); if (intersects.length > 0) { const hoveredSphere = intersects[0].object; if (this.highlighted !== hoveredSphere) { // Reset previous highlighted sphere if exists if (this.highlighted) { this.highlighted.material.color.setHex(this.highlighted.currentHex); } // Highlight new sphere this.highlighted = hoveredSphere; this.highlighted.currentHex = hoveredSphere.material.color.getHex(); this.highlighted.material.emissive.setHex(0xff0000); } } else { // No spheres hovered—reset highlight if (this.highlighted) { this.highlighted.material.color.setHex(this.highlighted.currentHex); this.highlighted = null; } } this.renderer.render(this.scene, this.camera); }
Quick Notes
- I removed the unnecessary
intersectHighlighteddata property since we recalculate the raycast hits every frame inrender. - Moved
rayCaster.setFromCameratorenderto ensure it uses the latest mouse position every frame. - Cleaned up the logic flow to make it more readable and ensure the highlight resets correctly when the mouse leaves all spheres.
This should fix the stuck highlight and make the raycasting respond properly as you move the mouse between spheres!
内容的提问来源于stack exchange,提问作者RaulS

