music(player): 加音量条 + 静音按钮(localStorage 持久化)
deploy music / build-and-deploy (push) Successful in 1m48s
deploy music / build-and-deploy (push) Successful in 1m48s
This commit is contained in:
@@ -230,6 +230,20 @@
|
||||
<div class="fill" :style="{ width: progressPct + '%' }"></div>
|
||||
</div>
|
||||
<span class="time">{{ fmtTime(duration) }}</span>
|
||||
<button
|
||||
class="btn-icon vol-icon"
|
||||
:title="muted ? '取消静音' : '静音'"
|
||||
@click="toggleMute"
|
||||
>{{ volIcon }}</button>
|
||||
<input
|
||||
class="vol-slider"
|
||||
type="range"
|
||||
min="0"
|
||||
max="100"
|
||||
:value="muted ? 0 : Math.round(volume * 100)"
|
||||
@input="onVolumeInput"
|
||||
title="音量"
|
||||
/>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@@ -336,6 +350,37 @@ const activeTagName = ref(null)
|
||||
const search = ref('')
|
||||
const sortMode = ref(localStorage.getItem('music.sort') || 'name')
|
||||
const repeatOne = ref(false)
|
||||
const volume = ref(parseFloat(localStorage.getItem('music.vol') || '1'))
|
||||
const muted = ref(localStorage.getItem('music.muted') === '1')
|
||||
|
||||
const volIcon = computed(() => {
|
||||
if (muted.value || volume.value === 0) return '🔇'
|
||||
if (volume.value < 0.34) return '🔈'
|
||||
if (volume.value < 0.67) return '🔉'
|
||||
return '🔊'
|
||||
})
|
||||
|
||||
function applyVolume() {
|
||||
if (audioEl.value) {
|
||||
audioEl.value.volume = volume.value
|
||||
audioEl.value.muted = muted.value
|
||||
}
|
||||
}
|
||||
|
||||
function onVolumeInput(e) {
|
||||
const v = parseInt(e.target.value, 10) / 100
|
||||
volume.value = isNaN(v) ? 0 : Math.max(0, Math.min(1, v))
|
||||
if (volume.value > 0 && muted.value) muted.value = false
|
||||
localStorage.setItem('music.vol', String(volume.value))
|
||||
localStorage.setItem('music.muted', muted.value ? '1' : '0')
|
||||
applyVolume()
|
||||
}
|
||||
|
||||
function toggleMute() {
|
||||
muted.value = !muted.value
|
||||
localStorage.setItem('music.muted', muted.value ? '1' : '0')
|
||||
applyVolume()
|
||||
}
|
||||
|
||||
const audioEl = ref(null)
|
||||
const lyricsBoxEl = ref(null)
|
||||
@@ -650,6 +695,7 @@ function onTimeUpdate(e) {
|
||||
|
||||
function onLoaded(e) {
|
||||
duration.value = e.target.duration || 0
|
||||
applyVolume()
|
||||
}
|
||||
|
||||
function onEnded() {
|
||||
@@ -1364,6 +1410,38 @@ onBeforeUnmount(() => {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.vol-icon { font-size: 16px; width: 32px; height: 32px; }
|
||||
.vol-slider {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
width: 90px;
|
||||
height: 4px;
|
||||
background: var(--border);
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.vol-slider:focus { outline: none; }
|
||||
.vol-slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background: var(--accent-strong);
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
}
|
||||
.vol-slider::-moz-range-thumb {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background: var(--accent-strong);
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.vol-slider { width: 60px; }
|
||||
}
|
||||
|
||||
/* Chat sidebar */
|
||||
.chat {
|
||||
width: 320px;
|
||||
|
||||
Reference in New Issue
Block a user