js 实现旗帜特效
使用 Canvas 实现旗帜飘动效果
通过 Canvas 绘制旗帜并模拟物理飘动效果,核心是利用正弦函数控制顶点位移:

const canvas = document.getElementById('flagCanvas');
const ctx = canvas.getContext('2d');
let time = 0;
function drawFlag() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
const flagWidth = 200, flagHeight = 120;
const segments = 20;
const amplitude = 15; // 波动幅度
ctx.fillStyle = '#FF0000';
ctx.beginPath();
// 旗帜左侧固定边
ctx.moveTo(100, 100);
// 创建波浪形右侧边
for (let i = 0; i <= segments; i++) {
const yPos = 100 + (flagHeight / segments) * i;
const xOffset = Math.sin(time + i * 0.3) * amplitude;
ctx.lineTo(100 + flagWidth + xOffset, yPos);
}
// 闭合路径
ctx.lineTo(100, 100 + flagHeight);
ctx.closePath();
ctx.fill();
time += 0.1;
requestAnimationFrame(drawFlag);
}
drawFlag();
CSS 动画实现旗帜效果
通过 CSS transform 和 filter 组合实现简易旗帜飘动:

<style>
.flag {
width: 200px;
height: 120px;
background: linear-gradient(90deg, red 0%, white 50%, blue 100%);
animation: wave 3s ease-in-out infinite alternate;
transform-origin: left center;
filter: drop-shadow(2px 4px 6px rgba(0,0,0,0.3));
}
@keyframes wave {
0% { transform: skewY(5deg); }
100% { transform: skewY(-5deg) scaleX(1.1); }
}
</style>
<div class="flag"></div>
SVG 路径动画实现
利用 SVG 路径变形实现更精细的旗帜效果:
<svg width="300" height="200">
<defs>
<path id="flagPath" d="M50,50 L250,50 C270,70 270,130 250,150 L50,150 Z" fill="red"/>
</defs>
<g transform="translate(0,20)">
<animateTransform
attributeName="transform"
type="translate"
values="0,0; 0,-5; 0,0"
dur="2s"
repeatCount="indefinite"/>
<use href="#flagPath">
<animate
attributeName="d"
values="M50,50 L250,50 C270,70 270,130 250,150 L50,150 Z;
M50,50 L250,45 C265,80 265,120 250,155 L50,150 Z;
M50,50 L250,55 C275,60 275,140 250,145 L50,150 Z"
dur="4s"
repeatCount="indefinite"/>
</use>
</g>
</svg>
Three.js 3D 旗帜效果
使用 Three.js 创建带有物理特性的 3D 旗帜:
import * as THREE from 'three';
import { Cloth } from 'three/examples/jsm/misc/Cloth';
const scene = new THREE.Scene();
const cloth = new Cloth(20, 20);
function createFlag() {
const clothGeometry = new THREE.ParametricBufferGeometry(
(u, v, target) => {
cloth.particles[u + v * cloth.w].position.toArray(target);
},
cloth.w, cloth.h
);
const material = new THREE.MeshBasicMaterial({
color: 0xff0000,
side: THREE.DoubleSide
});
const flag = new THREE.Mesh(clothGeometry, material);
scene.add(flag);
function animate() {
cloth.update(0.016);
clothGeometry.attributes.position.needsUpdate = true;
requestAnimationFrame(animate);
}
animate();
}
性能优化建议
- 对于简单效果优先使用 CSS 方案
- 需要复杂物理模拟时选择 Canvas/WebGL
- 使用 requestAnimationFrame 而非 setInterval
- 对 Canvas 绘制进行分层渲染
- 3D 场景中注意限制顶点数量
以上方案可根据实际需求调整参数,如增加纹理贴图、风场影响等增强真实感。






