快速开始
下面快速介绍如何将 AMLL 歌词组件集成到你的项目中。请注意,AMLL 不提供 CDN 引入方式,必须使用 bundler。
有关除组件库之外的其他周围工具包,请直接查阅 API 参考。
安装 AMLL 核心库:
npm install @applemusic-like-lyrics/corepnpm add @applemusic-like-lyrics/coreyarn add @applemusic-like-lyrics/core此外,AMLL 将一些图形与动画库声明为 peer,这是为了复用项目中可能存在的相关依赖。一些包管理器或配置下可能会自动安装 peer,若没有,需要手动安装。
npm install @pixi/app @pixi/core @pixi/display @pixi/filter-blur @pixi/filter-bulge-pinch @pixi/filter-color-matrix @pixi/sprite jss jss-preset-defaultpnpm add @pixi/app @pixi/core @pixi/display @pixi/filter-blur @pixi/filter-bulge-pinch @pixi/filter-color-matrix @pixi/sprite jss jss-preset-defaultyarn add @pixi/app @pixi/core @pixi/display @pixi/filter-blur @pixi/filter-bulge-pinch @pixi/filter-color-matrix @pixi/sprite jss jss-preset-default下面的示例会用 @applemusic-like-lyrics/lyric 解析 TTML 歌词文件。如果你的项目已经能直接提供 LyricLine[],可以跳过这个包。
npm install @applemusic-like-lyrics/lyricpnpm add @applemusic-like-lyrics/lyricyarn add @applemusic-like-lyrics/lyric接下来你可以使用原生包,也可以使用 React 或 Vue 绑定。
使用原生方式引入
Section titled “使用原生方式引入”AMLL 核心库是框架无关的。无论是否使用框架,均可使用此方法引入。
下面假设:
- 页面中已有
<audio id="audio">和<div id="lyric-player">,并给歌词容器设置了明确高度 - TTML 歌词文件在
/lyrics/song.ttml上提供
import { LyricPlayer } from "@applemusic-like-lyrics/core";import { parseTTML } from "@applemusic-like-lyrics/lyric";
// 一般地,打包器会处理 CSS 导入;如果出现异常,请查阅你使用的打包器文档import "@applemusic-like-lyrics/core/style.css";
const audio = document.querySelector("#audio");const playerHost = document.querySelector("#lyric-player");const player = new LyricPlayer();
playerHost.appendChild(player.getElement());
async function loadLyric() { const ttml = await fetch("/lyrics/song.ttml").then((res) => res.text()); const currentTime = Math.round(audio.currentTime * 1000); player.setLyricLines(parseTTML(ttml).lines, currentTime); player.setCurrentTime(currentTime, true);}
// 播放时持续同步音频进度let lastFrameTime = -1;function onFrame(frameTime) { const delta = lastFrameTime === -1 ? 0 : frameTime - lastFrameTime; lastFrameTime = frameTime;
if (!audio.paused) { player.setCurrentTime(Math.round(audio.currentTime * 1000)); }
player.update(delta); requestAnimationFrame(onFrame);}
audio.addEventListener("play", () => player.resume());audio.addEventListener("pause", () => player.pause());audio.addEventListener("seeked", () => { // 跳转后立即对齐歌词位置 player.setCurrentTime(Math.round(audio.currentTime * 1000), true);});
loadLyric();requestAnimationFrame(onFrame);有关更详细的时序管理,请转到 时序与生命周期。
你可以前往 API 参考:Core 核心 获取详细的接口文档。
使用 React 绑定
Section titled “使用 React 绑定”确保你已安装 react 和 react-dom 包。然后安装 AMLL React 绑定包:
npm install @applemusic-like-lyrics/reactpnpm add @applemusic-like-lyrics/reactyarn add @applemusic-like-lyrics/reactReact 绑定包拥有具名导出 LyricPlayer 作为核心组件。下面是一段示例,假设 TTML 歌词文件在 /lyrics/song.ttml 上提供、音频文件在 /music/song.m4a 上提供。
import { useEffect, useRef, useState } from "react";import type { LyricLine } from "@applemusic-like-lyrics/core";import { LyricPlayer } from "@applemusic-like-lyrics/react";import { parseTTML } from "@applemusic-like-lyrics/lyric";
// 一般地,打包器会处理 CSS 导入;如果出现异常,请查阅你使用的打包器文档import "@applemusic-like-lyrics/core/style.css";
function App() { const audioRef = useRef<HTMLAudioElement>(null); const [lyricLines, setLyricLines] = useState<LyricLine[]>([]); const [currentTime, setCurrentTime] = useState(0); const [playing, setPlaying] = useState(false);
function syncCurrentTime() { const audio = audioRef.current; if (audio) setCurrentTime(Math.round(audio.currentTime * 1000)); }
useEffect(() => { let canceled = false;
// parseTTML 返回包含元数据的对象,组件只需要其中的 lines fetch("/lyrics/song.ttml") .then((res) => res.text()) .then((ttml) => { if (!canceled) setLyricLines(parseTTML(ttml).lines); });
return () => { canceled = true; }; }, []);
useEffect(() => { let frameId = 0; const onFrame = () => { const audio = audioRef.current; if (audio && !audio.paused) { setCurrentTime(Math.round(audio.currentTime * 1000)); } frameId = requestAnimationFrame(onFrame); };
frameId = requestAnimationFrame(onFrame); return () => cancelAnimationFrame(frameId); }, []);
return ( <> <LyricPlayer lyricLines={lyricLines} currentTime={currentTime} playing={playing} style={{ height: 420 }} /> <audio ref={audioRef} src="/music/song.m4a" controls onPlay={() => setPlaying(true)} onPause={() => setPlaying(false)} onEnded={() => setPlaying(false)} onSeeked={syncCurrentTime} /> </> );}
export default App;你可以前往 API 参考:React 绑定 获取详细的接口文档。
使用 Vue 绑定
Section titled “使用 Vue 绑定”确保你已安装 Vue。然后安装 AMLL Vue 绑定包:
npm install @applemusic-like-lyrics/vuepnpm add @applemusic-like-lyrics/vueyarn add @applemusic-like-lyrics/vueVue 绑定包拥有具名导出 LyricPlayer 作为核心组件。歌词对象、播放进度等均以组件的响应式属性传入。下面是一段示例,假设 TTML 歌词文件在 /lyrics/song.ttml 上提供、音频文件在 /music/song.m4a 上提供。
<template> <LyricPlayer class="lyric-player" :lyric-lines="lyricLines" :current-time="currentTime" :playing="playing" /> <audio ref="audioEl" src="/music/song.m4a" controls @play="onPlay" @pause="onPause" @ended="onPause" @seeked="syncCurrentTime" /></template>
<script setup lang="ts">import type { LyricLine } from "@applemusic-like-lyrics/core";import { parseTTML } from "@applemusic-like-lyrics/lyric";import { LyricPlayer } from "@applemusic-like-lyrics/vue";import { onBeforeUnmount, onMounted, ref, shallowRef, useTemplateRef,} from "vue";
// 一般地,打包器会处理 CSS 导入;如果出现异常,请查阅你使用的打包器文档import "@applemusic-like-lyrics/core/style.css";
const audioEl = useTemplateRef<HTMLAudioElement>("audioEl");const lyricLines = shallowRef<LyricLine[]>([]);const currentTime = ref(0);const playing = ref(false);let frameId = 0;
async function loadLyric() { const ttml = await fetch("/lyrics/song.ttml").then((res) => res.text()); // parseTTML 返回包含元数据的对象,组件只需要其中的 lines lyricLines.value = parseTTML(ttml).lines;}
function syncCurrentTime() { if (audioEl.value) { currentTime.value = Math.round(audioEl.value.currentTime * 1000); }}
function onFrame() { syncCurrentTime(); if (playing.value) frameId = requestAnimationFrame(onFrame);}
function onPlay() { playing.value = true; cancelAnimationFrame(frameId); onFrame();}
function onPause() { playing.value = false; cancelAnimationFrame(frameId);}
onMounted(() => void loadLyric());onBeforeUnmount(() => cancelAnimationFrame(frameId));</script>
<style scoped>.lyric-player { height: 420px;}</style>你可以前往 API 参考:Vue 绑定 获取详细的接口文档。