如果处于小屏幕情况下播放视频,然后点击全屏播放按钮,模拟器上面播放后hbuildx就会出现报错,手机的话就会出现闪退,但是将同样的代码回退到 HBuilderX.5.26.2026091802 这个版本的重新打包并安装就不会有那个问题。
- 发布:2026-10-15 21:52
- 更新:2026-10-15 21:52
- 阅读:43
产品分类: uniapp/App
PC开发环境操作系统: Windows
PC开发环境操作系统版本号: win11
HBuilderX类型: 正式
HBuilderX版本号: 5.31
手机系统: Android
手机系统版本号: Android 15
手机厂商: 模拟器
手机机型: 荣耀magic8
页面类型: nvue
vue版本: vue3
打包方式: 云端
项目创建方式: HBuilderX
操作步骤:
预期结果:
无
无
实际结果:
无
无
bug描述:
<template>
<view v-if="visible" class="preview-overlay">
<view class="preview-header">
<text class="preview-close" @click="onClose">✕</text>
<text class="preview-name">{{ fileName }}</text>
<text class="preview-close" @click="onClose">✕</text>
</view>
<view class="preview-body">
<video v-if="previewType == 'video'" id="previewVideo" ref="videoRef" class="preview-video"
:title="fileName" :src="streamUrl" :show-loading="false" controls autoplay
@fullscreenchange="onVideoFullscreenchange" @longpress="onVideoLongPress" @touchend="onVideoTouchEnd"
@touchcancel="onVideoTouchEnd" @fullscreenclick="onVideoTouchEnd" />
<scroll-view v-if="previewType == 'text'" class="preview-text-scroll" direction="vertical"
:show-scrollbar="true">
<text v-if="loading" class="preview-loading">加载中...</text>
<text v-else class="preview-text-content">{{ textContent }}</text>
</scroll-view>
<view v-if="previewType == 'audio'" class="preview-audio">
<text class="preview-audio-icon">?</text>
<text class="preview-audio-name">{{ fileName }}</text>
<video class="preview-audio-player" :src="streamUrl" controls autoplay />
</view>
<view v-if="previewType == 'other'" class="preview-other">
<text class="preview-other-name">{{ fileName }}</text>
<text class="preview-other-tip">暂不支持预览此格式</text>
</view>
</view>
<view v-if="isMedia" class="preview-nav">
<text class="preview-nav-btn" @click="onPrev">‹ 上一个</text>
<text class="preview-nav-count">{{ currentIndex }} / {{ total }}</text>
<text class="preview-nav-btn" @click="onNext">下一个 ›</text>
</view>
</view>
</template>
<script setup lang="uts">
import { PropType } from 'vue'
import { FileItem } from "@/common/api-types.uts"
const props = defineProps({
visible: { type: Boolean, default: false },
previewType: { type: String, default: 'other' },
streamUrl: { type: String, default: '' },
textContent: { type: String, default: '' },
loading: { type: Boolean, default: false },
previewFile: { type: Object as PropType<FileItem | null>, default: null },
currentIndex: { type: Number, default: 0 },
total: { type: Number, default: 0 },
// 图片原生预览(uni.previewImage)使用的 URL 列表;为空时仅预览当前 streamUrl
urls: { type: Array as PropType<string[]>, default: () : string[] => [] as string[] }
})
const emit = defineEmits(['close', 'prev', 'next'])
// 由 previewFile 派生文件名,统一做 null 兼容,模板直接引用
const fileName = computed(() : string => props.previewFile != null ? props.previewFile!.name : '')
const isMedia = computed(() : boolean => props.previewType == 'video' || props.previewType == 'audio')
// 图片预览改用 uni-app x 自带的 uni.previewImage(原生全屏查看器,自带双指缩放、双击放大与左右滑动切换):
// 组件打开时若是图片,直接拉起原生预览并关闭自定义浮层,避免出现双层预览界面
watch(() : boolean => props.visible, (val : boolean) : void => {
if (!val || props.previewType != 'image') return
const urls = props.urls.length > 0 ? props.urls : [props.streamUrl]
// 用当前 streamUrl 在列表中定位索引,避免与媒体列表的显示序号混淆
let current = 0
for (let i = 0; i < urls.length; i++) {
if (urls[i] == props.streamUrl) {
current = i
break
}
}
uni.previewImage({
urls: urls,
current: current,
// 顶部数字指示器与循环预览:App 端生效;Web 端原生查看器暂不支持这两个参数,会自动忽略
indicator: 'number',
loop: true,
})
emit('close')
})
const onClose = () : void => { emit('close') }
const onPrev = () : void => { emit('prev') }
const onNext = () : void => { emit('next') }
const videoFullscreen = ref(false)
const onVideoFullscreenchange = (e : UniVideoFullScreenChangeEvent) : void => {
videoFullscreen.value = e.detail.fullScreen
}
const onVideoLongPress = () : void => {
const ctx = uni.createVideoContext('previewVideo')
if (ctx != null) {
ctx!.playbackRate(4)
}
}
const onVideoTouchEnd = () : void => {
const ctx = uni.createVideoContext('previewVideo')
if (ctx != null) {
ctx!.playbackRate(1)
}
}
const handleBack = () : boolean => {
if (videoFullscreen.value) {
const ctx = uni.createVideoContext('previewVideo')
if (ctx != null) {
ctx!.exitFullScreen()
}
videoFullscreen.value = false
return true
}
if (props.visible) {
emit('close')
return true
}
return false
}
defineExpose({ handleBack })
</script>
<style>
.preview-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 100;
background-color: #000000;
display: flex;
flex-direction: column;
}
.preview-header {
flex-direction: row;
align-items: center;
padding: 8px 12px;
background-color: rgba(0, 0, 0, 0.6);
/* #ifdef APP */
padding-top: 32px;
/* #endif */
}
.preview-name {
flex: 1;
font-size: 15px;
color: #FFFFFF;
lines: 1;
text-overflow: ellipsis;
}
.preview-close {
font-size: 28px;
color: #FF5252;
width: 44px;
height: 44px;
text-align: center;
}
.preview-body {
flex: 1;
height: 0;
width: 100%;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.preview-video {
width: 100%;
/* #ifdef H5 */
flex: 1;
/* #endif */
/* #ifdef APP */
height: 100%;
/* #endif */
}
.preview-text-scroll {
flex: 1;
width: 100%;
height: 0;
box-sizing: border-box;
padding: 16px;
background-color: #1A1A1A;
}
.preview-loading {
font-size: 14px;
color: #AAAAAA;
text-align: center;
}
.preview-text-content {
font-size: 14px;
color: #E0E0E0;
}
.preview-audio {
flex: 1;
align-items: center;
justify-content: center;
width: 100%;
}
.preview-audio-icon {
font-size: 64px;
margin-bottom: 12px;
}
.preview-audio-name {
font-size: 15px;
color: #FFFFFF;
margin-bottom: 16px;
}
.preview-audio-player {
width: 100%;
height: 60px;
}
.preview-other {
flex: 1;
align-items: center;
justify-content: center;
width: 100%;
}
.preview-other-name {
font-size: 16px;
color: #FFFFFF;
margin-bottom: 8px;
}
.preview-other-tip {
font-size: 13px;
color: #999999;
margin-bottom: 20px;
}
.preview-nav {
flex-direction: row;
justify-content: space-between;
padding: 12px 16px;
}
.preview-nav-btn {
font-size: 15px;
color: #FFFFFF;
padding: 10px 20px;
}
.preview-nav-count {
font-size: 12px;
color: #FFFFFF;
opacity: 0.85;
padding: 10px 0;
}
</style>
上面是我的源码,当点击全屏进行视频播放的时候,安卓端出现闪退。
hbuilderX 也存在报错,播放异常。下面是编辑器的报错信息。
18:56:56.524 at java.util.LinkedHashMap$LinkedHashIterator.nextNode(LinkedHashMap.java:760)
18:56:56.524 at java.util.LinkedHashMap$LinkedKeyIterator.next(LinkedHashMap.java:783)
18:56:56.524 at io.dcloud.uniapp.runtime.UniElementImpl.updateStyle$lambda$8(r8-map-id-30b99926c1bcbd04d3e0305c5e8709edfe6b947b61cf5180093a67349bbdca04:2)
18:56:56.524 at io.dcloud.uniapp.runtime.UniElementImpl.$r8$lambda$BE6uhWU3JspkG5-0lH7eGpderpU(Unknown Source:0)
18:56:56.525 at io.dcloud.uniapp.runtime.UniElementImpl$$ExternalSyntheticLambda1.invoke(D8$$SyntheticClass:0)
18:56:56.525 at io.dcloud.uniapp.util.AppTimeTrace$Companion.recordTimeMethod(r8-map-id-30b99926c1bcbd04d3e0305c5e8709edfe6b947b61cf5180093a67349bbdca04:6)
18:56:56.525 at io.dcloud.uniapp.runtime.UniElementImpl.updateStyle(r8-map-id-30b99926c1bcbd04d3e0305c5e8709edfe6b947b61cf5180093a67349bbdca04:5)
18:56:56.525 at io.dcloud.px.p3.a(r8-map-id-30b99926c1bcbd04d3e0305c5e8709edfe6b947b61cf5180093a67349bbdca04:217)
18:56:56.525 at io.dcloud.px.p3$$ExternalSyntheticLambda0.onLayoutChange(D8$$SyntheticClass:0)
18:56:56.525 at android.view.View.layout(View.java:23221)
18:56:56.525 at android.view.ViewGroup.layout(ViewGroup.java:6412)
18:56:56.525 at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
18:56:56.525 at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
18:56:56.526 at android.view.View.layout(View.java:23203)
18:56:56.526 at android.view.ViewGroup.layout(ViewGroup.java:6412)
18:56:56.526 at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
18:56:56.527 at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673)
18:56:56.527 at android.widget.LinearLayout.onLayout(LinearLayout.java:1582)
18:56:56.528 at android.view.View.layout(View.java:23203)
18:56:56.528 at android.view.ViewGroup.layout(ViewGroup.java:6412)
18:56:56.529 at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
18:56:56.529 at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
18:56:56.529 at android.view.View.layout(View.java:23203)
18:56:56.529 at android.view.ViewGroup.layout(ViewGroup.java:6412)
18:56:56.530 at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
18:56:56.530 at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673)
18:56:56.530 at android.widget.LinearLayout.onLayout(LinearLayout.java:1582)
18:56:56.531 at android.view.View.layout(View.java:23203)
18:56:56.531 at android.view.ViewGroup.layout(ViewGroup.java:6412)
18:56:56.531 at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
18:56:56.532 at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
18:56:56.532 at com.android.internal.policy.DecorView.onLayout(DecorView.java:802)
18:56:56.532 at android.view.View.layout(View.java:23203)
18:56:56.533 at android.view.ViewGroup.layout(ViewGroup.java:6412)
18:56:56.533 at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:3756)
18:56:56.533 at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3212)
18:56:56.533 at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2186)
18:56:56.534 at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8833)
18:56:56.534 at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1047)
18:56:56.534 at android.view.Choreographer.doCallbacks(Choreographer.java:845)
18:56:56.535 at android.view.Choreographer.doFrame(Choreographer.java:780)
18:56:56.535 at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1032)
18:56:56.535 at android.os.Handler.handleCallback(Handler.java:938)
18:56:56.535 at android.os.Handler.dispatchMessage(Handler.java:99)
18:56:56.536 at android.os.Looper.loopOnce(Looper.java:201)
18:56:56.536 at android.os.Looper.loop(Looper.java:288)
18:56:56.536 at io.dcloud.px.c3.a(r8-map-id-30b99926c1bcbd04d3e0305c5e8709edfe6b947b61cf5180093a67349bbdca04:66)
18:56:56.536 at io.dcloud.px.c3$$ExternalSyntheticLambda0.run(D8$$SyntheticClass:0)
18:56:56.536 at android.os.Handler.handleCallback(Handler.java:938)
18:56:56.536 at android.os.Handler.dispatchMessage(Handler.java:99)
18:56:56.537 at android.os.Looper.loopOnce(Looper.java:201)
18:56:56.537 at android.os.Looper.loop(Looper.java:288)
18:56:56.537 at android.app.ActivityThread.main(ActivityThread.java:8085)
18:56:56.537 at java.lang.reflect.Method.invoke(Native Method)
18:56:56.538 at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
18:56:56.538 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1091)