mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-14 06:30:49 +08:00
feat: 移动端歌词点击跳转 优化国际化和移动端逐字歌词
This commit is contained in:
@@ -29,7 +29,8 @@ export default {
|
||||
list: 'Next'
|
||||
},
|
||||
lrc: {
|
||||
noLrc: 'No lyrics, please enjoy'
|
||||
noLrc: 'No lyrics, please enjoy',
|
||||
noAutoScroll: 'This lyrics does not support auto-scroll'
|
||||
},
|
||||
reparse: {
|
||||
title: 'Select Music Source',
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
# 日本語翻訳 (Japanese Translation)
|
||||
|
||||
このディレクトリには、AlgerMusicPlayerの日本語翻訳ファイルが含まれています。
|
||||
|
||||
## ファイル構成
|
||||
|
||||
- `artist.ts` - アーティスト関連の翻訳
|
||||
- `common.ts` - 共通の翻訳(ボタン、メッセージなど)
|
||||
- `comp.ts` - コンポーネント関連の翻訳
|
||||
- `donation.ts` - 寄付関連の翻訳
|
||||
- `download.ts` - ダウンロード管理の翻訳
|
||||
- `favorite.ts` - お気に入り機能の翻訳
|
||||
- `history.ts` - 履歴機能の翻訳
|
||||
- `login.ts` - ログイン関連の翻訳
|
||||
- `player.ts` - プレイヤー機能の翻訳
|
||||
- `search.ts` - 検索機能の翻訳
|
||||
- `settings.ts` - 設定画面の翻訳
|
||||
- `songItem.ts` - 楽曲アイテムの翻訳
|
||||
- `user.ts` - ユーザー関連の翻訳
|
||||
- `index.ts` - すべての翻訳をエクスポートするメインファイル
|
||||
|
||||
## 使用方法
|
||||
|
||||
アプリケーション内で言語を日本語に切り替えるには:
|
||||
|
||||
1. 設定画面を開く
|
||||
2. 「言語設定」セクションを見つける
|
||||
3. ドロップダウンメニューから「日本語」を選択
|
||||
|
||||
## 翻訳の改善
|
||||
|
||||
翻訳の改善や修正がある場合は、該当するファイルを編集してプルリクエストを送信してください。
|
||||
|
||||
## 注意事項
|
||||
|
||||
- すべての翻訳キーは中国語版と英語版に対応しています
|
||||
- 新しい機能が追加された場合は、対応する日本語翻訳も追加する必要があります
|
||||
- 文字化けを避けるため、ファイルはUTF-8エンコーディングで保存してください
|
||||
@@ -29,7 +29,8 @@ export default {
|
||||
list: '自動で次の曲を再生'
|
||||
},
|
||||
lrc: {
|
||||
noLrc: '歌詞がありません。お楽しみください'
|
||||
noLrc: '歌詞がありません。お楽しみください',
|
||||
noAutoScroll: '本歌詞は自動スクロールをサポートしていません'
|
||||
},
|
||||
reparse: {
|
||||
title: '解析音源を選択',
|
||||
|
||||
@@ -29,7 +29,8 @@ export default {
|
||||
list: '자동으로 다음 곡 재생'
|
||||
},
|
||||
lrc: {
|
||||
noLrc: '가사가 없습니다. 음악을 감상해주세요'
|
||||
noLrc: '가사가 없습니다. 음악을 감상해주세요',
|
||||
noAutoScroll: '본 가사는 자동 스크롤을 지원하지 않습니다'
|
||||
},
|
||||
reparse: {
|
||||
title: '음원 선택',
|
||||
|
||||
@@ -29,7 +29,8 @@ export default {
|
||||
list: '自动播放下一个'
|
||||
},
|
||||
lrc: {
|
||||
noLrc: '暂无歌词, 请欣赏'
|
||||
noLrc: '暂无歌词, 请欣赏',
|
||||
noAutoScroll: '本歌词不支持自动滚动'
|
||||
},
|
||||
reparse: {
|
||||
title: '选择解析音源',
|
||||
|
||||
@@ -29,7 +29,8 @@ export default {
|
||||
list: '自動播放下一個'
|
||||
},
|
||||
lrc: {
|
||||
noLrc: '暫無歌詞, 請欣賞'
|
||||
noLrc: '暫無歌詞, 請欣賞',
|
||||
noAutoScroll: '本歌詞不支持自動滾動'
|
||||
},
|
||||
reparse: {
|
||||
title: '選擇解析音源',
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
</div>
|
||||
<!-- 无时间戳歌词提示 -->
|
||||
<div v-if="!supportAutoScroll" class="music-lrc-text no-scroll-tip">
|
||||
<span>本歌词不支持自动滚动</span>
|
||||
<span>{{ t('player.lrc.noAutoScroll') }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-for="(item, index) in lrcArray"
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
<div class="lyrics-padding-top"></div>
|
||||
<!-- 无时间戳歌词提示 -->
|
||||
<div v-if="!supportAutoScroll" class="lyric-line no-scroll-tip">
|
||||
<span>本歌词不支持自动滚动</span>
|
||||
<span>{{ t('player.lrc.noAutoScroll') }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-for="(item, index) in lrcArray"
|
||||
@@ -62,7 +62,7 @@
|
||||
'now-text': index === nowIndex,
|
||||
'hover-text': item.text && item.startTime !== -1
|
||||
}"
|
||||
@click="item.startTime !== -1 ? jumpToLyricTime(index) : null"
|
||||
@click="item.startTime !== -1 ? setAudioTime(index) : null"
|
||||
>
|
||||
<!-- 逐字歌词显示 -->
|
||||
<div
|
||||
@@ -143,14 +143,14 @@
|
||||
v-if="line.hasWordByWord && line.words && line.words.length > 0"
|
||||
class="word-by-word-lyric"
|
||||
>
|
||||
<span
|
||||
v-for="(word, wordIndex) in line.words"
|
||||
:key="wordIndex"
|
||||
class="lyric-word"
|
||||
:style="getWordStyle(line.originalIndex, wordIndex, word)"
|
||||
<template v-for="(word, wordIndex) in line.words" :key="wordIndex">
|
||||
<span
|
||||
class="lyric-word"
|
||||
:style="getWordStyle(line.originalIndex, wordIndex, word)"
|
||||
>
|
||||
{{ word.text }}</span
|
||||
><span v-if="word.space"> </span></template
|
||||
>
|
||||
{{ word.text }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- 普通歌词显示 -->
|
||||
<span v-else>{{ line.text }}</span>
|
||||
@@ -253,7 +253,7 @@
|
||||
<div class="lyrics-padding-top"></div>
|
||||
<!-- 无时间戳歌词提示 -->
|
||||
<div v-if="!supportAutoScroll" class="lyric-line no-scroll-tip">
|
||||
<span>本歌词不支持自动滚动</span>
|
||||
<span>{{ t('player.lrc.noAutoScroll') }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-for="(item, index) in lrcArray"
|
||||
@@ -264,7 +264,7 @@
|
||||
'now-text': index === nowIndex,
|
||||
'hover-text': item.text && item.startTime !== -1
|
||||
}"
|
||||
@click="item.startTime !== -1 ? jumpToLyricTime(index) : null"
|
||||
@click="item.startTime !== -1 ? setAudioTime(index) : null"
|
||||
>
|
||||
<!-- 逐字歌词显示 -->
|
||||
<div
|
||||
@@ -371,10 +371,12 @@ import { useI18n } from 'vue-i18n';
|
||||
import {
|
||||
allTime,
|
||||
artistList,
|
||||
correctionTime,
|
||||
lrcArray,
|
||||
nowIndex,
|
||||
nowTime,
|
||||
playMusic,
|
||||
setAudioTime,
|
||||
sound,
|
||||
textColors,
|
||||
useLyricProgress
|
||||
@@ -431,6 +433,7 @@ const isTouchScrolling = ref(false);
|
||||
const touchStartY = ref(0);
|
||||
const lastScrollTop = ref(0);
|
||||
const autoScrollTimer = ref<number | null>(null);
|
||||
const isSongChanging = ref(false);
|
||||
|
||||
// 横屏检测相关
|
||||
const { width, height } = useWindowSize();
|
||||
@@ -530,6 +533,9 @@ const scrollToCurrentLyric = (immediate = false, customScrollerRef?: HTMLElement
|
||||
watch(nowIndex, (newIndex, oldIndex) => {
|
||||
console.log(`歌词索引变化: ${oldIndex} -> ${newIndex}`);
|
||||
|
||||
// 歌曲切换时不自动滚动
|
||||
if (isSongChanging.value) return;
|
||||
|
||||
// 在竖屏全屏歌词模式下滚动
|
||||
if (showFullLyrics.value) {
|
||||
nextTick(() => {
|
||||
@@ -980,6 +986,38 @@ watch(
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
// 添加对 playMusic.id 的监听,歌曲切换时滚动到顶部
|
||||
watch(
|
||||
() => playMusic.value.id,
|
||||
(newId, oldId) => {
|
||||
// 只在歌曲真正切换时滚动到顶部
|
||||
if (newId !== oldId && newId) {
|
||||
isSongChanging.value = true;
|
||||
// 延迟滚动,确保 nowIndex 已重置
|
||||
setTimeout(() => {
|
||||
// 在全屏歌词模式下滚动到顶部
|
||||
if (showFullLyrics.value && lyricsScrollerRef.value) {
|
||||
lyricsScrollerRef.value.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
// 在横屏模式下滚动到顶部
|
||||
else if (isLandscape.value && landscapeLyricsRef.value) {
|
||||
landscapeLyricsRef.value.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
// 延迟恢复自动滚动,等待歌词数据更新
|
||||
setTimeout(() => {
|
||||
isSongChanging.value = false;
|
||||
}, 300);
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 加载保存的配置
|
||||
onMounted(() => {
|
||||
const savedConfig = localStorage.getItem('music-full-config');
|
||||
@@ -1024,42 +1062,6 @@ watch(isVisible, (newVal) => {
|
||||
}
|
||||
});
|
||||
|
||||
// 通过点击跳转到歌词对应时间点
|
||||
const jumpToLyricTime = (index: number) => {
|
||||
if (lrcArray.value[index] && 'time' in lrcArray.value[index] && sound.value) {
|
||||
// 使用类型断言确保time属性存在
|
||||
const lrcItem = lrcArray.value[index] as { time: number; text: string; trText?: string };
|
||||
const time = lrcItem.time / 1000;
|
||||
|
||||
// 更新播放位置
|
||||
sound.value.seek(time);
|
||||
nowTime.value = time;
|
||||
|
||||
// 显示反馈动画 - 处理两种模式下的歌词行
|
||||
const normalEl = document.getElementById(`lyric-line-${index}`);
|
||||
const landscapeEl = document.getElementById(`landscape-lyric-line-${index}`);
|
||||
|
||||
// 根据当前模式获取正确的元素并添加动画效果
|
||||
const activeEl = isLandscape.value ? landscapeEl : normalEl;
|
||||
|
||||
if (activeEl) {
|
||||
activeEl.classList.add('clicked');
|
||||
setTimeout(() => {
|
||||
activeEl.classList.remove('clicked');
|
||||
}, 300);
|
||||
}
|
||||
|
||||
// 如果歌词索引没有变化(例如点击当前行),手动触发滚动
|
||||
if (nowIndex.value === index) {
|
||||
if (isLandscape.value && !showFullLyrics.value) {
|
||||
scrollToCurrentLyric(true, landscapeLyricsRef.value);
|
||||
} else if (showFullLyrics.value) {
|
||||
scrollToCurrentLyric(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 添加getLrcStyle函数
|
||||
const { getLrcStyle: originalLrcStyle } = useLyricProgress();
|
||||
|
||||
@@ -1101,8 +1103,8 @@ const getWordStyle = (lineIndex: number, _wordIndex: number, word: any) => {
|
||||
};
|
||||
}
|
||||
|
||||
// 当前行的逐字效果
|
||||
const currentTime = nowTime.value * 1000; // 转换为毫秒,确保与word时间单位一致
|
||||
// 当前行的逐字效果,应用歌词矫正时间
|
||||
const currentTime = (nowTime.value + correctionTime.value) * 1000; // 转换为毫秒,确保与word时间单位一致
|
||||
|
||||
// 直接使用绝对时间比较
|
||||
const wordStartTime = word.startTime; // 单词开始的绝对时间(毫秒)
|
||||
@@ -1874,6 +1876,10 @@ const getWordStyle = (lineIndex: number, _wordIndex: number, word: any) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.word-by-word-lyric {
|
||||
@apply justify-start;
|
||||
}
|
||||
}
|
||||
|
||||
.unified-controls {
|
||||
|
||||
Reference in New Issue
Block a user