Frontend Lab
← 回到所有效果
T053D005three

Hover Image Plane

hover 互動平面

難度 ★★★★★標籤 hover · pointer · three3 min read

效果簡述

R3F 物件接受 onPointerOver / onPointerOut 像 DOM 一樣。可以做 hover 放大、變色、旋轉。這 demo 用簡單的 plane,實務上換成貼圖即可。

預設|hover 變色

Claude Code Prompt

💬 Claude Code Prompt
參考:3D005 hover image plane
技術:r3f pointer events + useFrame 緩動

具體行為:
- mesh onPointerOver/Out 設 hover state
- useFrame 裡用 lerp 緩動到目標 scale
- 不要用 CSS transition(三維沒有)

限制:
- 行動裝置沒 hover,要 fallback(觸控時直接 active)
- pointer events 需要 mesh 在最上層,沒被遮擋
- raycaster 對 plane 雙面:material 設 side={THREE.DoubleSide} 避免背面點不到

完整程式碼

HoverImagePlane.tsx
'use client'

import { Canvas, useFrame } from '@react-three/fiber'
import { useRef, useState } from 'react'
import type { Mesh } from 'three'

function ImagePlane() {
const ref = useRef<Mesh>(null)
const [hover, setHover] = useState(false)
useFrame((_, d) => {
  const m = ref.current; if (!m) return
  const t = hover ? 1.15 : 1
  m.scale.x += (t - m.scale.x) * d * 6
  m.scale.y += (t - m.scale.y) * d * 6
})
return (
  <mesh ref={ref} onPointerOver={() => setHover(true)} onPointerOut={() => setHover(false)}>
    <planeGeometry args={[3, 1.7, 32, 32]} />
    <meshBasicMaterial color={hover ? '#fb923c' : '#c2410c'} />
  </mesh>
)
}

export function HoverImagePlane() {
return (
  <Canvas camera={{ position: [0,0,4], fov: 50 }} dpr={[1,2]}>
    <ambientLight intensity={1} />
    <ImagePlane />
  </Canvas>
)
}

何時用

  • ✅ 3D 卡片網格(hover 突出)
  • ✅ 作品縮圖
  • ✅ 配 GLTF 模型 hover 互動

何時別用

  • ❌ 行動為主用戶
  • ❌ 一頁很多 hover 元素(事件衝突)
  • ❌ 對 hit test 要求高的精細互動

我踩過的坑

  1. 沒緩動瞬移:直接 set scale 看起來廉價,lerp 緩動才對味。

  2. plane 背面點不到:DoubleSide 才確保 raycaster 能擊中。

  3. 手機沒 hover:要設定 onPointerDown 作為 fallback。

相關效果

搜尋

按 ⌘K 隨時開啟