React歌词滚动效果(跟随音乐播放时间滚动)

首先给audio绑定更新时间事件

复制代码
	const updateTime = e => {
		console.log(e.target.currentTime)
		setCurrentTime(e.target.currentTime);
	};


	<audio
				src={currentSong.url}
				ref={audio}
				onCanPlay={ready}
				onEnded={end}
				onTimeUpdate={updateTime}
			></audio>

当歌曲播放时间改变的时候会触发updateTime事件,如下所示

歌词json格式

复制代码
[
    {
        "time": 2,
        "content": "采样曲:願い~あの頃のキミへ~",
        "contents": [
            "采样曲:願い~あの頃のキミへ~"
        ]
    },
    {
        "time": 12,
        "content": "中文填词:一只然",
        "contents": [
            "中文填词:一只然"
        ]
    },
    {
        "time": 15,
        "content": "OP(原属词曲版权公司):テレビ東京ミュージック 东京电视台音乐",
        "contents": [
            "OP(原属词曲版权公司):テレビ東京ミュージック 东京电视台音乐"
        ]
    },
    {
        "time": 19,
        "content": "本作品经过原词曲作者以及版权公司授权",
        "contents": [
            "本作品经过原词曲作者以及版权公司授权"
        ]
    },
    ......
    ]

接下来就是根据当前的播放时间显示歌词高亮,给歌词绑定高亮放大样式

复制代码
.highlight {
color: $theme-color;
font-weight: $font-weight-bold;
font-size: 16px !important;
}

// 使用Redux的useSelector获取当前播放时间
const currentTime = useSelector(state => state.musicReducer.currentTime);

// 使用React的useMemo优化性能,只有当currentTime变化时,才会重新计算time的值
const time= useMemo(() => {
    return currentTime;
},[currentTime]);

// updateTime函数用于更新当前歌词的索引
const updateTime = e => {
    // 在所有歌词中找到第一个时间大于当前播放时间的歌词,其前一个歌词就是当前应该显示的歌词
    const currentLyricIndex = lyric.findIndex((lyricItem, index) => {
        // 判断是否是最后一项歌词,如果是,下一项歌词的时间设为无穷大
        const isLastItem = index === lyric.length - 1;
        const nextLyricTime = isLastItem ? Infinity : lyric[index + 1].time;
        // 如果当前播放时间在当前歌词和下一条歌词的时间之间,说明当前歌词应该被显示
        return time >= lyricItem.time && time < nextLyricTime;
    });
    // 更新当前歌词的索引
    setCurrentLyricIndex(currentLyricIndex);
};

// 使用React的useEffect在time变化时,调用updateTime函数,更新当前歌词的索引
useEffect(() => {
    updateTime()
}, [time]);

time发生变化时,调用updateTime函数来更新当前歌词的索引currentLyricIndex。确保在歌曲播放过程中,歌词随着时间的推移而更新。

最后,实现歌词滚动的效果

  1. 创建 scrollRef

    复制代码
    const scrollRef = useRef();

    使用 useRef 创建了一个 scrollRef,用于引用 Scroll 组件的实例。

  2. 使用 useEffect 进行歌词滚动:

    复制代码
        useEffect(() => {
            // 模拟异步加载歌词
            // 假设你要滚动到的歌词元素有一个特定的类名 ".lyric-item.highlight"
            const selector = '.lyric-item.highlight';
            // 调用 Scroll 组件的 scrollToElement 方法
            if (scrollRef.current) {
                scrollRef.current.scrollToElement(selector, 500); // 第二个参数是滚动时间,可以根据需要调整
            }
        }, [currentLyricIndex]);

    currentLyricIndex 发生变化时,useEffect 会被触发。在该效果中,它模拟异步加载歌词,然后通过 scrollRef.current.scrollToElement 方法滚动到指定的歌词元素,滚动时间为500毫秒。这样,每次歌词发生变化时都会滚动到当前高亮的歌词位置。

  3. Scroll 组件的 scrollToElement 方法实现:

    复制代码
            scrollToElement(selector, time = 0) {
                if (bScroll) {
                    const targetElement = document.querySelector(selector);
                    if (targetElement) {
                        const containerHeight = scrollContainerRef.current.clientHeight;
                        const targetHeight = targetElement.clientHeight;
                        const offsetTop = (containerHeight - targetHeight) / 2;
                        bScroll.scrollToElement(targetElement, time, 0, -offsetTop);
                    }
                }
            }

    这是 Scroll 组件内部的 scrollToElement 方法的实现。首先,通过 document.querySelector(selector) 获取到目标元素(具有指定类名的高亮歌词元素)。然后,计算目标元素相对于滚动容器的偏移,最后使用 bScroll.scrollToElement 将目标元素滚动到可视区域,传入的参数包括时间、水平和垂直的偏移。

相关推荐
中微子8 分钟前
JavaScript 防抖与节流:从原理到实践的完整指南
前端·javascript
天天向上102423 分钟前
Vue 配置打包后可编辑的变量
前端·javascript·vue.js
芬兰y39 分钟前
VUE 带有搜索功能的穿梭框(简单demo)
前端·javascript·vue.js
好果不榨汁1 小时前
qiankun 路由选择不同模式如何书写不同的配置
前端·vue.js
小蜜蜂dry1 小时前
Fetch 笔记
前端·javascript
拾光拾趣录1 小时前
列表分页中的快速翻页竞态问题
前端·javascript
小old弟1 小时前
vue3,你看setup设计详解,也是个人才
前端
Lefan1 小时前
一文了解什么是Dart
前端·flutter·dart
Patrick_Wilson1 小时前
青苔漫染待客迟
前端·设计模式·架构
vvilkim1 小时前
Nuxt.js 全面测试指南:从单元测试到E2E测试
开发语言·javascript·ecmascript