直播:音量与全屏叠在画面底部,全屏内可调
Made-with: Cursor
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
class="live-room-video live-room-video--watch live-room-video--contain"
|
||||
playsinline
|
||||
autoplay
|
||||
@volumechange="syncVolumeUIFromVideo"
|
||||
></video>
|
||||
<div class="live-dm-layer" aria-hidden="true">
|
||||
<div
|
||||
@@ -37,11 +38,29 @@
|
||||
<span class="live-dm-from">{{ d.from }}:</span>{{ d.text }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="live-video-toolbar" role="toolbar" aria-label="播放控制">
|
||||
<button type="button" class="live-video-toolbtn" @click="unmuteAndPlay">开声音</button>
|
||||
<button type="button" class="live-video-toolbtn" @click="toggleStageFullscreen">
|
||||
{{ stageFullscreen ? '退出全屏' : '全屏' }}
|
||||
</button>
|
||||
<div class="live-video-overlay" role="toolbar" aria-label="播放与音量">
|
||||
<div class="live-video-overlay-inner">
|
||||
<button type="button" class="live-overlay-btn" @click="toggleMute">
|
||||
{{ displayMuted ? '开声音' : '静音' }}
|
||||
</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>
|
||||
@@ -102,6 +121,9 @@ import { getSiteDmToken, getSiteDmUsername, clearSiteDmSession } from '../utils/
|
||||
const watchVideoRef = ref(null)
|
||||
const liveStageRef = ref(null)
|
||||
const stageFullscreen = ref(false)
|
||||
/** 与 video.volume / muted 同步(浏览器自动播放可能先静音) */
|
||||
const volumePercent = ref(100)
|
||||
const displayMuted = ref(false)
|
||||
const rawLiveUrl = ref('')
|
||||
const pageTitle = ref('视频直播')
|
||||
const watchStatus = ref('正在检测本站直播…')
|
||||
@@ -180,11 +202,37 @@ function goLiveRoom() {
|
||||
window.location.href = target
|
||||
}
|
||||
|
||||
function unmuteAndPlay() {
|
||||
function syncVolumeUIFromVideo() {
|
||||
const v = watchVideoRef.value
|
||||
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(() => {})
|
||||
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() {
|
||||
@@ -384,6 +432,8 @@ onMounted(async () => {
|
||||
watchStatus.value = s
|
||||
}
|
||||
})
|
||||
await nextTick()
|
||||
syncVolumeUIFromVideo()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
@@ -529,11 +579,6 @@ onUnmounted(() => {
|
||||
aspect-ratio: unset;
|
||||
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:-webkit-full-screen .live-stage-footer {
|
||||
flex-shrink: 0;
|
||||
@@ -547,6 +592,86 @@ onUnmounted(() => {
|
||||
.live-stage:-webkit-full-screen .live-dm-hint {
|
||||
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 {
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
@@ -674,28 +799,6 @@ onUnmounted(() => {
|
||||
color: #ffb86c;
|
||||
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 {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user