以下是一个实现动态海洋和天空效果的 Vue 3 Composition API Hook,使用 Canvas 绘制动画效果:

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'// 动态海洋和天空效果 Hook
export function useOceanSky(canvasRef) {const ctx = ref(null)const animationFrame = ref(null)const time = ref(0)// 初始化画布const initCanvas = () => {const canvas = canvasRef.valuecanvas.width = canvas.clientWidthcanvas.height = canvas.clientHeightctx.value = canvas.getContext('2d')}// 绘制天空渐变const drawSky = () => {const gradient = ctx.value.createLinearGradient(0, 0, 0, canvasRef.value.height * 0.6)gradient.addColorStop(0, '#6bb9f0')  // 顶部浅蓝gradient.addColorStop(0.5, '#3498db') // 中部中蓝gradient.addColorStop(1, '#2980b9')   // 底部深蓝ctx.value.fillStyle = gradientctx.value.fillRect(0, 0, canvasRef.value.width, canvasRef.value.height * 0.6)}// 绘制动态海洋const drawOcean = () => {const waveHeight = 15const waveSpeed = 0.01const oceanHeight = canvasRef.value.height * 0.4// 海洋基础色ctx.value.fillStyle = '#1a5276'ctx.value.fillRect(0, canvasRef.value.height * 0.6,canvasRef.value.width, oceanHeight)// 绘制波浪ctx.value.beginPath()ctx.value.moveTo(0, canvasRef.value.height * 0.6)for (let x = 0; x <= canvasRef.value.width; x += 5) {const y = canvasRef.value.height * 0.6 + Math.sin(x * 0.02 + time.value) * waveHeightctx.value.lineTo(x, y)}ctx.value.lineTo(canvasRef.value.width, canvasRef.value.height)ctx.value.lineTo(0, canvasRef.value.height)ctx.value.closePath()// 波浪渐变const waveGradient = ctx.value.createLinearGradient(0, canvasRef.value.height * 0.6, 0, canvasRef.value.height * 0.6 + waveHeight * 2)waveGradient.addColorStop(0, 'rgba(127, 179, 213, 0.7)')waveGradient.addColorStop(1, 'rgba(26, 82, 118, 0.3)')ctx.value.fillStyle = waveGradientctx.value.fill()// 更新时间time.value += waveSpeed}// 绘制太阳/月亮const drawSun = () => {const sunSize = 60const sunX = canvasRef.value.width * 0.8const sunY = canvasRef.value.height * 0.2 + Math.sin(time.value * 0.5) * 20// 光晕效果const gradient = ctx.value.createRadialGradient(sunX, sunY, 0, sunX, sunY, sunSize * 2)gradient.addColorStop(0, 'rgba(255, 204, 0, 0.8)')gradient.addColorStop(1, 'rgba(255, 204, 0, 0)')ctx.value.fillStyle = gradientctx.value.beginPath()ctx.value.arc(sunX, sunY, sunSize * 2, 0, Math.PI * 2)ctx.value.fill()// 太阳主体ctx.value.fillStyle = '#FFCC00'ctx.value.beginPath()ctx.value.arc(sunX, sunY, sunSize, 0, Math.PI * 2)ctx.value.fill()}// 动画循环const animate = () => {if (!ctx.value) return// 清除画布ctx.value.clearRect(0, 0, canvasRef.value.width, canvasRef.value.height)// 绘制场景drawSky()drawOcean()drawSun()// 继续动画animationFrame.value = requestAnimationFrame(animate)}// 响应式调整const handleResize = () => {initCanvas()}// 生命周期onMounted(() => {initCanvas()animate()window.addEventListener('resize', handleResize)})onUnmounted(() => {cancelAnimationFrame(animationFrame.value)window.removeEventListener('resize', handleResize)})
}
</script>

使用示例

<template><div class="scene"><canvas ref="canvas" class="ocean-sky-canvas"></canvas></div>
</template><script setup>
import { ref } from 'vue'
import { useOceanSky } from './useOceanSky'const canvas = ref(null)
useOceanSky(canvas)
</script><style>
.ocean-sky-canvas {width: 100vw;height: 100vh;display: block;
}
.scene {overflow: hidden;
}
</style>

功能说明

  1. 动态天空
  • 三层渐变蓝色天空
  • 随时间变化的太阳位置(含光晕效果)
  1. 海洋效果
  • 深蓝色海洋基底
  • 使用正弦函数生成动态波浪
  • 波浪表面半透明渐变效果
  1. 动画系统
  • 基于 requestAnimationFrame 的动画循环
  • 自适应窗口大小变化
  • 组件卸载时自动清理资源
  1. 性能优化
  • 使用 Canvas 2D 上下文绘制
  • 避免不必要的重绘
  • 使用径向渐变实现自然光晕

此 Hook 创建了一个自包含的动画系统,可通过调整参数(如波浪高度、太阳大小等)轻松定制视觉效果。