ow
This commit is contained in:
1 parent
6417562c4f
commit
f1e6e116c3
31 files changed
+2065
-309
No files matched your search
@@ -51,6 +51,46 @@ function setControls(v: boolean): void {
|
||||
}
|
||||
watch(() => props.controls, v => (localControls.value = v ?? true));
|
||||
|
||||
/**
|
||||
* App 端 <video> 是原生控件层:DOM 节点、cover-view 都会被整层盖住,
|
||||
* 只有 plus 原生视图能画在画面上,所以左上角返回改用它绘制(H5 走模板里的 vp-back)。
|
||||
*/
|
||||
let backView: any = null;
|
||||
function mountNativeBack(): void {
|
||||
const ViewCtor = plus.nativeObj.View as any;
|
||||
if (!ViewCtor) {
|
||||
return;
|
||||
}
|
||||
// 原生视图不受页面布局影响,而 webview 是沉浸式的(从屏幕顶部开始):
|
||||
// 自己在 24rpx 边距上叠加系统状态栏高度,与 H5 的 .vp-back 保持一致
|
||||
const btn = Math.round(uni.upx2px(72)) || 41;
|
||||
const gap = Math.round(uni.upx2px(24)) || 14;
|
||||
const statusH = uni.getSystemInfoSync().statusBarHeight || 0;
|
||||
backView = new ViewCtor("vp-native-back", {
|
||||
top: `${gap + statusH}px`,
|
||||
left: `${gap}px`,
|
||||
width: `${btn}px`,
|
||||
height: `${btn}px`,
|
||||
// View 默认白底,透明后只剩下面绘制的内容
|
||||
backgroundColor: "rgba(0,0,0,0)",
|
||||
});
|
||||
// 半透明圆底 + 白色 "<":uview 图标字体在 App 端只有 woff2(原生字体不支持),用系统字形 "‹" 代替;
|
||||
// 与 H5 的 .vp-back / 音乐厅 .vap-back 同款:rgba(0,0,0,0.22) 圆底、无描边
|
||||
backView.drawRect(
|
||||
{ color: "rgba(0,0,0,0.22)", radius: `${btn / 2}px` },
|
||||
{ top: "0px", left: "0px", width: `${btn}px`, height: `${btn}px` },
|
||||
"vp-back-bg",
|
||||
);
|
||||
backView.drawText(
|
||||
"‹",
|
||||
{ top: "0px", left: "0px", width: `${btn}px`, height: `${btn}px` },
|
||||
{ color: "#FFFFFF", size: `${Math.round(btn * 0.82)}px`, align: "center" },
|
||||
"vp-back-glyph",
|
||||
);
|
||||
backView.addEventListener("click", () => emit("close"));
|
||||
backView.show();
|
||||
}
|
||||
|
||||
const isPlaying = ref(false);
|
||||
const buffering = ref(false);
|
||||
const currentTime = ref(0);
|
||||
@@ -268,6 +308,11 @@ function loadCurrent(autoplay: boolean): void {
|
||||
}
|
||||
|
||||
function toggle(): void {
|
||||
// 控制区收起时,点画面先把控制条叫回来(App 端画面上的恢复按钮会被原生层盖住)
|
||||
if (!controlsVisible.value) {
|
||||
setControls(true);
|
||||
return;
|
||||
}
|
||||
ensureCtx();
|
||||
if (isPlaying.value) {
|
||||
ctx?.pause();
|
||||
@@ -623,6 +668,9 @@ const progressPercent = computed(() => (duration.value > 0 ? Math.min(100, (curr
|
||||
const bufferPercent = computed(() => Math.min(100, Math.max(0, bufferedRatio.value * 100)));
|
||||
|
||||
onMounted(() => {
|
||||
// #ifdef APP-PLUS
|
||||
mountNativeBack();
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
const el = getInnerVideo();
|
||||
nativeHlsOk.value = !!(el?.canPlayType
|
||||
@@ -634,6 +682,12 @@ onMounted(() => {
|
||||
nextTick(() => measureBar());
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
// #ifdef APP-PLUS
|
||||
if (backView) {
|
||||
backView.close();
|
||||
backView = null;
|
||||
}
|
||||
// #endif
|
||||
destroyHls();
|
||||
if (sleepTimer) {
|
||||
clearTimeout(sleepTimer);
|
||||
@@ -657,7 +711,7 @@ watch(controlsVisible, (v) => {
|
||||
|
||||
<template>
|
||||
<view class="vp">
|
||||
<!-- 顶部:仅返回,绝对定位浮在画面上不占布局高度(列表入口在底部控制区 ≡) -->
|
||||
<!-- 左上角返回:浮在画面上不占布局(App 端该位置被视频原生层盖住,由 plus 原生视图绘制,见 mountNativeBack) -->
|
||||
<view v-if="controlsVisible" class="vp-back" @click="emit('close')">
|
||||
<u-icon name="arrow-left" size="40" color="#ffffff" />
|
||||
</view>
|
||||
@@ -686,7 +740,7 @@ watch(controlsVisible, (v) => {
|
||||
<u-icon name="play-right-fill" size="80" color="#ffffff" />
|
||||
</view>
|
||||
|
||||
<!-- 收起控制区后的恢复入口 -->
|
||||
<!-- 收起控制区后的恢复入口(H5;App 端该位置被视频层盖住,改为点画面恢复) -->
|
||||
<view v-if="!controlsVisible" class="vp-restore" @click="toggleControls">
|
||||
<u-icon name="eye" size="34" color="#ffffff" />
|
||||
</view>
|
||||
@@ -825,8 +879,15 @@ watch(controlsVisible, (v) => {
|
||||
|
||||
.vp-back {
|
||||
position: absolute;
|
||||
top: calc(16rpx + var(--status-bar-height));
|
||||
left: 16rpx;
|
||||
/* 与音乐厅 .vap-back 完全一致(同尺寸/同底色/无描边) */
|
||||
/* App 端用 uni 注入的状态栏高度避让;H5 用 safe-area */
|
||||
/* #ifdef APP-PLUS */
|
||||
top: calc(24rpx + var(--status-bar-height, 0px));
|
||||
/* #endif */
|
||||
/* #ifndef APP-PLUS */
|
||||
top: calc(24rpx + env(safe-area-inset-top));
|
||||
/* #endif */
|
||||
left: 24rpx;
|
||||
z-index: 20;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -834,7 +895,7 @@ watch(controlsVisible, (v) => {
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 50%;
|
||||
background: rgba(0, 0, 0, 0.28);
|
||||
background: rgba(0, 0, 0, 0.22);
|
||||
}
|
||||
|
||||
.vp-stage {
|
||||
@@ -844,7 +905,8 @@ watch(controlsVisible, (v) => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #000;
|
||||
/* 空态不铺黑:透出 .vp 的青绿渐变,与音乐厅同底色,半透明圆钮才看得见 */
|
||||
background: transparent;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -913,12 +975,12 @@ watch(controlsVisible, (v) => {
|
||||
top: 24rpx;
|
||||
right: 24rpx;
|
||||
z-index: 9;
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 50%;
|
||||
background: rgba(6, 56, 62, 0.5);
|
||||
border: 2rpx solid rgba(255, 255, 255, 0.45);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user