You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

react-wavesurfer技术问题:点击区域播放与按钮移除区域实现

我来帮你解决这两个react-wavesurfer的问题,这两个需求都可以通过wavesurfer.js的Region插件来实现,下面是具体的步骤和代码示例:


一、点击区域时从起始位置播放至结束位置

要实现这个功能,核心是利用wavesurfer.js的Region插件提供的区域点击事件,结合wavesurfer的播放控制API来完成。这里分两种场景演示:

场景1:直接使用wavesurfer.js + React

import React, { useRef, useEffect } from 'react';
import WaveSurfer from 'wavesurfer.js';
import RegionPlugin from 'wavesurfer.js/dist/plugins/regions.js';

const AudioPlayer = () => {
  const containerRef = useRef(null);
  const wavesurferRef = useRef(null);

  useEffect(() => {
    if (!containerRef.current) return;

    // 初始化wavesurfer并加载Region插件
    const wavesurfer = WaveSurfer.create({
      container: containerRef.current,
      waveColor: '#4F4A85',
      progressColor: '#383351',
      plugins: [RegionPlugin.create()]
    });

    // 加载音频文件
    wavesurfer.load('/path/to/your/audio.mp3');
    wavesurferRef.current = wavesurfer;

    // 监听区域点击事件
    wavesurfer.on('region-click', (region, event) => {
      // 阻止默认的区域拖拽行为(不需要拖拽可忽略)
      event.stopPropagation();

      // 先暂停当前播放,避免冲突
      wavesurfer.pause();
      // 从区域起始位置播放,到结束位置自动暂停
      wavesurfer.play(region.start, region.end);
    });

    // 组件卸载时清理资源
    return () => wavesurfer.destroy();
  }, []);

  return <div ref={containerRef} style={{ width: '100%', height: '100px' }} />;
};

export default AudioPlayer;

说明:

  • wavesurfer.play(start, end) 是官方API,传入起始/结束时间(单位:秒),播放到终点会自动暂停。
  • 如果你的wavesurfer版本不支持带参数的play方法,可以手动监听音频进度控制暂停:
    wavesurfer.on('region-click', (region, event) => {
      event.stopPropagation();
      wavesurfer.pause();
      // 跳转到区域起始位置(seekTo接收0-1的比例值)
      wavesurfer.seekTo(region.start / wavesurfer.getDuration());
      wavesurfer.play();
    
      // 监听音频进度,到达终点时暂停
      const stopAtEnd = () => {
        if (wavesurfer.getCurrentTime() >= region.end) {
          wavesurfer.pause();
          // 移除监听避免内存泄漏
          wavesurfer.off('audioprocess', stopAtEnd);
        }
      };
      wavesurfer.on('audioprocess', stopAtEnd);
    });
    

场景2:使用封装好的react-wavesurfer组件(如@dschoon/react-wavesurfer)

通过ref获取wavesurfer实例后,逻辑和上面一致:

import React, { useRef, useEffect } from 'react';
import WaveSurfer from '@dschoon/react-wavesurfer';
import RegionPlugin from 'wavesurfer.js/dist/plugins/regions.js';

const AudioPlayer = () => {
  const waveSurferRef = useRef(null);

  useEffect(() => {
    const wavesurfer = waveSurferRef.current?.wavesurfer;
    if (!wavesurfer) return;

    wavesurfer.on('region-click', (region, event) => {
      event.stopPropagation();
      wavesurfer.pause();
      wavesurfer.play(region.start, region.end);
    });

    return () => wavesurfer.off('region-click');
  }, []);

  return (
    <WaveSurfer
      ref={waveSurferRef}
      options={{
        waveColor: '#4F4A85',
        progressColor: '#383351',
        plugins: [RegionPlugin.create()]
      }}
      url="/path/to/your/audio.mp3"
    />
  );
};

export default AudioPlayer;

二、点击按钮移除指定区域

要实现移除区域,需要保存每个创建的Region实例,调用实例的remove()方法,同时同步更新React状态保证UI一致:

import React, { useRef, useEffect, useState } from 'react';
import WaveSurfer from 'wavesurfer.js';
import RegionPlugin from 'wavesurfer.js/dist/plugins/regions.js';

const AudioPlayer = () => {
  const containerRef = useRef(null);
  const wavesurferRef = useRef(null);
  const [regions, setRegions] = useState([]);

  useEffect(() => {
    if (!containerRef.current) return;

    const wavesurfer = WaveSurfer.create({
      container: containerRef.current,
      waveColor: '#4F4A85',
      progressColor: '#383351',
      plugins: [RegionPlugin.create()]
    });

    wavesurfer.load('/path/to/your/audio.mp3');
    wavesurferRef.current = wavesurfer;

    // 监听区域创建,保存实例到状态
    wavesurfer.on('region-created', (region) => {
      setRegions(prev => [...prev, region]);
    });

    // 监听区域移除,同步更新状态
    wavesurfer.on('region-removed', (removedRegion) => {
      setRegions(prev => prev.filter(region => region.id !== removedRegion.id));
    });

    return () => wavesurfer.destroy();
  }, []);

  // 示例:创建测试区域(可替换为自定义创建逻辑)
  const createTestRegion = () => {
    wavesurferRef.current?.addRegion({
      start: 1,
      end: 3,
      color: 'rgba(255, 0, 0, 0.2)',
      id: `region-${Date.now()}` // 自定义ID方便区分
    });
  };

  // 移除指定区域
  const removeRegion = (region) => {
    region.remove(); // 调用实例方法,自动触发region-removed事件
  };

  return (
    <div>
      <div ref={containerRef} style={{ width: '100%', height: '100px', marginBottom: '1rem' }} />
      <button onClick={createTestRegion} style={{ marginBottom: '1rem' }}>创建测试区域</button>
      <div>
        {regions.map(region => (
          <div key={region.id} style={{ marginBottom: '0.5rem' }}>
            区域 {region.id}: {region.start.toFixed(2)}s - {region.end.toFixed(2)}s
            <button onClick={() => removeRegion(region)} style={{ marginLeft: '1rem' }}>移除</button>
          </div>
        ))}
      </div>
    </div>
  );
};

export default AudioPlayer;

说明:

  • 每个Region实例自带remove()方法,调用后会从wavesurfer中移除区域,并触发region-removed事件。
  • 通过监听region-removed事件更新React状态,确保页面列表和实际区域一致。
  • 使用React封装组件时,获取wavesurfer实例的方式和第一个问题一致,逻辑完全相同。

内容的提问来源于stack exchange,提问作者Boss Vinh Nguyen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:48:21