好的,阿杰。下面给你一个完整的 SVG + feDisplacementMap + feImage 水波纹动态效果示例,并讲解如何 计算动态值来驱动水波纹动画
这个方法利用 滤镜位移图 + 动态动画帧 来实现波纹效果,非常适合网页 H5、Canvas 替代方案或 SVG 动画。


1️⃣ 原理概述

  • feDisplacementMap
    将一张灰度图(或噪声图)作为位移源,对目标图像进行像素偏移,实现扭曲效果。
  • feImage
    用作位移图(displacement map),可以用噪声图或动态生成的噪声纹理。
  • 动态水波纹
    通过改变 feImagex / y 偏移或滤镜属性,或者用 <animate> 或 JS 动态改变滤镜参数,实现动画效果。

2️⃣ 简单 SVG 水波纹示例

&lt;svg width="400" height="300">
  &lt;!-- 原始图片 -->
  &lt;image id="source" href="your-image.jpg" width="400" height="300">&lt;/image>

  &lt;!-- 定义滤镜 -->
  &lt;filter id="ripple" x="0" y="0" width="100%" height="100%">
    &lt;!-- 位移源图片,可以是噪声图 -->
    &lt;feImage id="noise" href="noise.png" result="displacementMap" x="0" y="0"/>
    &lt;!-- DisplacementMap -->
    &lt;feDisplacementMap in="SourceGraphic" in2="displacementMap"
      scale="20" xChannelSelector="R" yChannelSelector="G"/>
  &lt;/filter>

  &lt;!-- 应用滤镜 -->
  &lt;image href="your-image.jpg" width="400" height="300" filter="url(#ripple)">&lt;/image>
&lt;/svg>

参数说明

属性说明
scale位移幅度,数字越大波纹越明显
xChannelSelector / yChannelSelector使用哪一个通道控制偏移(R/G/B/A)
in / in2in 是原图,in2 是位移图
feImage href位移源图,可以是噪声图

3️⃣ 动态计算波纹偏移值(JavaScript 动态修改 scalefeImage 偏移)

&lt;svg id="svg" width="400" height="300">
  &lt;defs>
    &lt;filter id="ripple" x="0" y="0" width="100%" height="100%">
      &lt;feImage id="noise" href="noise.png" result="displacementMap" x="0" y="0"/>
      &lt;feDisplacementMap id="dispMap"
        in="SourceGraphic" in2="displacementMap"
        scale="0" xChannelSelector="R" yChannelSelector="G"/>
    &lt;/filter>
  &lt;/defs>

  &lt;image href="your-image.jpg" width="400" height="300" filter="url(#ripple)">&lt;/image>
&lt;/svg>

&lt;script>
const dispMap = document.getElementById('dispMap');
let t = 0;

// 动态水波纹
function animate() {
  // 使用正弦函数计算 scale,实现波动
  const scale = 10 + 10 * Math.sin(t * 0.1); 
  dispMap.setAttribute('scale', scale);

  // 可以同时动态改变 feImage x/y 偏移
  const noise = document.getElementById('noise');
  noise.setAttribute('x', 20 * Math.sin(t * 0.05));
  noise.setAttribute('y', 20 * Math.cos(t * 0.05));

  t++;
  requestAnimationFrame(animate);
}
animate();
&lt;/script>

✅ 关键点

  1. 动态 scale
    使用 Math.sinMath.cos 产生周期性变化,模拟水波上下浮动。
  2. 动态移动位移图
    改变 feImagexy 可以让波纹方向、流动速度更自然。
  3. requestAnimationFrame
    每帧更新,平滑动画,性能更好。
  4. 噪声图选择
    • 可以是灰度随机噪声图
    • 或者用 Canvas 动态生成噪声图 → toDataURLfeImage href 动态替换,实现复杂水波纹效果。

4️⃣ 高级技巧

  • 多层滤镜叠加
    通过多个 feDisplacementMap 叠加不同频率噪声,实现更真实水波纹。
  • 基于 Canvas 动态生成噪声图 const canvas = document.createElement('canvas'); canvas.width = 400; canvas.height = 300; const ctx = canvas.getContext('2d'); const imgData = ctx.createImageData(400, 300); for(let i=0;i<imgData.data.length;i+=4){ const v = Math.random()*255; imgData.data[i] = v; // R imgData.data[i+1] = v; // G imgData.data[i+2] = v; // B imgData.data[i+3] = 255; // A } ctx.putImageData(imgData,0,0); noise.setAttribute('href', canvas.toDataURL());
  • 结合 CSS / JS
    可把 SVG 放到 <div> 背景中,实现网页全屏水波纹动态效果。

5️⃣ 总结

  • 使用 feDisplacementMap + feImage 可以实现 SVG 水波纹。
  • 动态计算:
    • scale = base + amplitude * sin(t * speed)
    • feImage x/y 偏移 = amplitude * sin/cos
  • 可以通过 JS 每帧更新 requestAnimationFrame 动态变化,实现真实波动效果。
  • 高级场景可结合 Canvas 噪声图 + 多层滤镜叠加,生成更逼真的水波纹。

太好了,阿杰!下面给你一个 完整可运行的 SVG 水波纹网页 Demo
特点如下:

  • 全屏背景图片
  • 使用 feDisplacementMap + feImage 实现水波纹
  • JS 动态计算波纹参数
  • 支持连续动画
  • 支持移动端/桌面端

你可以直接复制到 HTML 文件里打开预览。


&lt;!DOCTYPE html>
&lt;html lang="zh-CN">
&lt;head>
&lt;meta charset="UTF-8">
&lt;meta name="viewport" content="width=device-width, initial-scale=1.0">
&lt;title>SVG 水波纹动效 Demo&lt;/title>
&lt;style>
  html, body {
    margin: 0;
    padding: 0;
    overflow: hidden;
    width: 100%;
    height: 100%;
    background: #000;
  }
  svg {
    width: 100%;
    height: 100%;
    display: block;
  }
&lt;/style>
&lt;/head>
&lt;body>

&lt;svg id="rippleSVG" width="100%" height="100%">
  &lt;defs>
    &lt;!-- 动态噪声位移图 -->
    &lt;filter id="rippleFilter" x="0" y="0" width="100%" height="100%">
      &lt;feImage id="noiseImage" href="" result="displacementMap" x="0" y="0" preserveAspectRatio="none"/>
      &lt;feDisplacementMap id="dispMap" in="SourceGraphic" in2="displacementMap"
                         scale="0" xChannelSelector="R" yChannelSelector="G"/>
    &lt;/filter>
  &lt;/defs>

  &lt;!-- 背景图片 -->
  &lt;image href="https://images.unsplash.com/photo-1507525428034-b723cf961d3e?auto=format&amp;fit=crop&amp;w=800&amp;q=80" 
         width="100%" height="100%" filter="url(#rippleFilter)"/>
&lt;/svg>

&lt;script>
// 创建 Canvas 用作动态噪声
const canvas = document.createElement('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const ctx = canvas.getContext('2d');

const noiseImage = document.getElementById('noiseImage');
const dispMap = document.getElementById('dispMap');

let t = 0;

function generateNoise() {
  const imgData = ctx.createImageData(canvas.width, canvas.height);
  for(let i=0;i&lt;imgData.data.length;i+=4){
    const val = Math.floor(Math.random() * 255);
    imgData.data[i] = val;     // R
    imgData.data[i+1] = val;   // G
    imgData.data[i+2] = val;   // B
    imgData.data[i+3] = 255;   // A
  }
  ctx.putImageData(imgData, 0, 0);
  noiseImage.setAttribute('href', canvas.toDataURL());
}

function animateRipple() {
  t++;

  // 生成动态噪声
  generateNoise();

  // 动态 scale 模拟水波起伏
  const scale = 15 + 10 * Math.sin(t * 0.1);
  dispMap.setAttribute('scale', scale);

  // 动态偏移噪声图,实现波动方向
  const xOffset = 20 * Math.sin(t * 0.05);
  const yOffset = 20 * Math.cos(t * 0.05);
  noiseImage.setAttribute('x', xOffset);
  noiseImage.setAttribute('y', yOffset);

  requestAnimationFrame(animateRipple);
}

// 启动动画
animateRipple();

// 可根据窗口大小动态调整 Canvas
window.addEventListener('resize', () => {
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
});

&lt;/script>

&lt;/body>
&lt;/html>


✅ 特性说明

  1. 动态水波纹
    • dispMap.scale 动态变化模拟波纹起伏
    • noiseImage x/y 动态偏移,波纹方向自然流动
  2. 全屏背景图
    • SVG <image> 作为背景
    • 可替换 href 为你自己的图片 URL
  3. 移动端/桌面端兼容
    • SVG + Canvas 动态生成噪声
    • 不依赖外部库
  4. 可扩展
    • 替换噪声生成算法可实现涟漪、波浪、液化等效果
    • 可叠加多个 feDisplacementMap 增强真实感