直播:音量与全屏叠在画面底部,全屏内可调
Made-with: Cursor
This commit is contained in:
@@ -26,6 +26,7 @@
|
|||||||
class="live-room-video live-room-video--watch live-room-video--contain"
|
class="live-room-video live-room-video--watch live-room-video--contain"
|
||||||
playsinline
|
playsinline
|
||||||
autoplay
|
autoplay
|
||||||
|
@volumechange="syncVolumeUIFromVideo"
|
||||||
></video>
|
></video>
|
||||||
<div class="live-dm-layer" aria-hidden="true">
|
<div class="live-dm-layer" aria-hidden="true">
|
||||||
<div
|
<div
|
||||||
@@ -37,11 +38,29 @@
|
|||||||
<span class="live-dm-from">{{ d.from }}:</span>{{ d.text }}
|
<span class="live-dm-from">{{ d.from }}:</span>{{ d.text }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="live-video-toolbar" role="toolbar" aria-label="播放控制">
|
<div class="live-video-overlay" role="toolbar" aria-label="播放与音量">
|
||||||
<button type="button" class="live-video-toolbtn" @click="unmuteAndPlay">开声音</button>
|
<div class="live-video-overlay-inner">
|
||||||
<button type="button" class="live-video-toolbtn" @click="toggleStageFullscreen">
|
<button type="button" class="live-overlay-btn" @click="toggleMute">
|
||||||
{{ stageFullscreen ? '退出全屏' : '全屏' }}
|
{{ displayMuted ? '开声音' : '静音' }}
|
||||||
</button>
|
</button>
|
||||||
|
<label class="live-vol-wrap">
|
||||||
|
<span class="live-vol-label">音量</span>
|
||||||
|
<input
|
||||||
|
class="live-vol-range"
|
||||||
|
type="range"
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
|
step="1"
|
||||||
|
:value="volumePercent"
|
||||||
|
aria-label="音量"
|
||||||
|
@input="onVolumeRangeInput"
|
||||||
|
/>
|
||||||
|
<span class="live-vol-value" aria-hidden="true">{{ volumePercent }}%</span>
|
||||||
|
</label>
|
||||||
|
<button type="button" class="live-overlay-btn" @click="toggleStageFullscreen">
|
||||||
|
{{ stageFullscreen ? '退出全屏' : '全屏' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -102,6 +121,9 @@ import { getSiteDmToken, getSiteDmUsername, clearSiteDmSession } from '../utils/
|
|||||||
const watchVideoRef = ref(null)
|
const watchVideoRef = ref(null)
|
||||||
const liveStageRef = ref(null)
|
const liveStageRef = ref(null)
|
||||||
const stageFullscreen = ref(false)
|
const stageFullscreen = ref(false)
|
||||||
|
/** 与 video.volume / muted 同步(浏览器自动播放可能先静音) */
|
||||||
|
const volumePercent = ref(100)
|
||||||
|
const displayMuted = ref(false)
|
||||||
const rawLiveUrl = ref('')
|
const rawLiveUrl = ref('')
|
||||||
const pageTitle = ref('视频直播')
|
const pageTitle = ref('视频直播')
|
||||||
const watchStatus = ref('正在检测本站直播…')
|
const watchStatus = ref('正在检测本站直播…')
|
||||||
@@ -180,11 +202,37 @@ function goLiveRoom() {
|
|||||||
window.location.href = target
|
window.location.href = target
|
||||||
}
|
}
|
||||||
|
|
||||||
function unmuteAndPlay() {
|
function syncVolumeUIFromVideo() {
|
||||||
const v = watchVideoRef.value
|
const v = watchVideoRef.value
|
||||||
if (!v) return
|
if (!v) return
|
||||||
v.muted = false
|
displayMuted.value = v.muted
|
||||||
|
volumePercent.value = Math.round(Math.min(1, Math.max(0, v.volume)) * 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onVolumeRangeInput(e) {
|
||||||
|
volumePercent.value = Number(e.target.value)
|
||||||
|
const v = watchVideoRef.value
|
||||||
|
if (!v) return
|
||||||
|
v.volume = volumePercent.value / 100
|
||||||
|
v.muted = volumePercent.value === 0
|
||||||
v.play().catch(() => {})
|
v.play().catch(() => {})
|
||||||
|
displayMuted.value = v.muted
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleMute() {
|
||||||
|
const v = watchVideoRef.value
|
||||||
|
if (!v) return
|
||||||
|
if (v.muted) {
|
||||||
|
v.muted = false
|
||||||
|
if (v.volume === 0) {
|
||||||
|
v.volume = 1
|
||||||
|
volumePercent.value = 100
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
v.muted = true
|
||||||
|
}
|
||||||
|
v.play().catch(() => {})
|
||||||
|
syncVolumeUIFromVideo()
|
||||||
}
|
}
|
||||||
|
|
||||||
function syncStageFullscreenFlag() {
|
function syncStageFullscreenFlag() {
|
||||||
@@ -384,6 +432,8 @@ onMounted(async () => {
|
|||||||
watchStatus.value = s
|
watchStatus.value = s
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
await nextTick()
|
||||||
|
syncVolumeUIFromVideo()
|
||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
@@ -529,11 +579,6 @@ onUnmounted(() => {
|
|||||||
aspect-ratio: unset;
|
aspect-ratio: unset;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
.live-stage:fullscreen .live-video-toolbar,
|
|
||||||
.live-stage:-webkit-full-screen .live-video-toolbar {
|
|
||||||
flex-shrink: 0;
|
|
||||||
margin-top: 8px;
|
|
||||||
}
|
|
||||||
.live-stage:fullscreen .live-stage-footer,
|
.live-stage:fullscreen .live-stage-footer,
|
||||||
.live-stage:-webkit-full-screen .live-stage-footer {
|
.live-stage:-webkit-full-screen .live-stage-footer {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
@@ -547,6 +592,86 @@ onUnmounted(() => {
|
|||||||
.live-stage:-webkit-full-screen .live-dm-hint {
|
.live-stage:-webkit-full-screen .live-dm-hint {
|
||||||
max-width: none;
|
max-width: none;
|
||||||
}
|
}
|
||||||
|
.live-video-overlay {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 6;
|
||||||
|
padding: 20px 10px 10px;
|
||||||
|
border-radius: 0 0 14px 14px;
|
||||||
|
background: linear-gradient(to top, rgba(0, 0, 0, 0.82) 0%, rgba(0, 0, 0, 0.45) 55%, transparent 100%);
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
.live-video-overlay-inner {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 8px 12px;
|
||||||
|
}
|
||||||
|
.live-overlay-btn {
|
||||||
|
padding: 6px 14px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid rgba(0, 212, 255, 0.5);
|
||||||
|
background: rgba(0, 0, 0, 0.45);
|
||||||
|
color: #00d4ff;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s, border-color 0.2s;
|
||||||
|
}
|
||||||
|
.live-overlay-btn:hover {
|
||||||
|
background: rgba(0, 212, 255, 0.18);
|
||||||
|
border-color: rgba(0, 212, 255, 0.85);
|
||||||
|
}
|
||||||
|
.live-vol-wrap {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
min-width: 0;
|
||||||
|
flex: 1;
|
||||||
|
justify-content: flex-end;
|
||||||
|
max-width: min(280px, 58vw);
|
||||||
|
}
|
||||||
|
.live-vol-label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: rgba(255, 255, 255, 0.75);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.live-vol-value {
|
||||||
|
font-size: 12px;
|
||||||
|
color: rgba(255, 255, 255, 0.65);
|
||||||
|
width: 2.5em;
|
||||||
|
text-align: right;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.live-vol-range {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 72px;
|
||||||
|
height: 6px;
|
||||||
|
border-radius: 3px;
|
||||||
|
appearance: none;
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
accent-color: #00d4ff;
|
||||||
|
}
|
||||||
|
.live-vol-range::-webkit-slider-thumb {
|
||||||
|
appearance: none;
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #00d4ff;
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.35);
|
||||||
|
}
|
||||||
|
.live-vol-range::-moz-range-thumb {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #00d4ff;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
.live-dm-layer {
|
.live-dm-layer {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -674,28 +799,6 @@ onUnmounted(() => {
|
|||||||
color: #ffb86c;
|
color: #ffb86c;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
.live-video-toolbar {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 10px;
|
|
||||||
justify-content: center;
|
|
||||||
margin-top: 12px;
|
|
||||||
}
|
|
||||||
.live-video-toolbtn {
|
|
||||||
padding: 8px 18px;
|
|
||||||
border-radius: 10px;
|
|
||||||
border: 1px solid rgba(0, 212, 255, 0.45);
|
|
||||||
background: rgba(0, 212, 255, 0.12);
|
|
||||||
color: #00d4ff;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 600;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background 0.2s, border-color 0.2s;
|
|
||||||
}
|
|
||||||
.live-video-toolbtn:hover {
|
|
||||||
background: rgba(0, 212, 255, 0.22);
|
|
||||||
border-color: rgba(0, 212, 255, 0.75);
|
|
||||||
}
|
|
||||||
.live-room-actions {
|
.live-room-actions {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user