替换原有的固定比例方案,改为通过视频实际宽高动态计算适配比例,移除冗余的harmonyVideoHeight计算方法,统一多端样式处理逻辑,优化鸿蒙端视频高度计算方式
296 lines
6.3 KiB
Vue
296 lines
6.3 KiB
Vue
<template>
|
||
<view class="video-container" :style="containerStyle">
|
||
<!-- H5端使用原生video标签 -->
|
||
<!-- #ifdef H5 -->
|
||
<video
|
||
ref="videoRef"
|
||
data-component-name="diy-video"
|
||
class="diy-video h5-video"
|
||
:src="videoUrl"
|
||
:poster="posterUrl"
|
||
:style="videoWarpCss"
|
||
controls
|
||
preload="metadata"
|
||
@loadedmetadata="onVideoLoaded"
|
||
@click="handlerClick(videoUrl)"
|
||
></video>
|
||
<!-- #endif -->
|
||
|
||
<!-- 微信小程序端使用uni-app的video组件 -->
|
||
<!-- #ifdef MP-WEIXIN -->
|
||
<video
|
||
ref="videoRef"
|
||
data-component-name="diy-video"
|
||
class="diy-video mp-video"
|
||
:src="videoUrl"
|
||
:poster="posterUrl"
|
||
:style="videoWarpCss"
|
||
controls
|
||
object-fit="cover"
|
||
@loadedmetadata="onVideoLoaded"
|
||
@error="onVideoError"
|
||
></video>
|
||
<!-- #endif -->
|
||
|
||
<!-- 鸿蒙元服务端使用uni-app的video组件 -->
|
||
<!-- #ifdef MP-HARMONY -->
|
||
<video
|
||
ref="videoRef"
|
||
data-component-name="diy-video"
|
||
class="diy-video harmony-video"
|
||
:src="videoUrl"
|
||
:poster="posterUrl"
|
||
:style="videoWarpCss"
|
||
controls
|
||
object-fit="cover"
|
||
@loadedmetadata="onVideoLoaded"
|
||
@error="onVideoError"
|
||
></video>
|
||
<!-- #endif -->
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
// 视频
|
||
import DiyMinx from './minx.js'
|
||
export default {
|
||
name: 'diy-video',
|
||
props: {
|
||
value: {
|
||
type: Object
|
||
}
|
||
},
|
||
data() {
|
||
return {
|
||
videoWidth: 0,
|
||
videoHeight: 0,
|
||
videoUrl: '',
|
||
posterUrl: '',
|
||
windowWidth: 0
|
||
};
|
||
},
|
||
created() {
|
||
this.initVideoData();
|
||
this.initWindowWidth();
|
||
},
|
||
mixins: [DiyMinx],
|
||
watch: {
|
||
value: {
|
||
immediate: true,
|
||
handler(newVal) {
|
||
if (newVal) {
|
||
this.initVideoData();
|
||
}
|
||
}
|
||
}
|
||
},
|
||
computed: {
|
||
videoWarpCss: function () {
|
||
var obj = '';
|
||
if (this.value && this.value.componentAngle == 'round') {
|
||
obj += 'border-top-left-radius:' + this.value.topAroundRadius * 2 + 'rpx;';
|
||
obj += 'border-top-right-radius:' + this.value.topAroundRadius * 2 + 'rpx;';
|
||
obj += 'border-bottom-left-radius:' + this.value.bottomAroundRadius * 2 + 'rpx;';
|
||
obj += 'border-bottom-right-radius:' + this.value.bottomAroundRadius * 2 + 'rpx;';
|
||
}
|
||
return obj;
|
||
},
|
||
// 动态计算容器比例
|
||
containerStyle() {
|
||
let style = '';
|
||
const defaultRatio = 9 / 16;
|
||
|
||
let ratio = defaultRatio;
|
||
if (this.videoWidth && this.videoHeight) {
|
||
ratio = this.videoHeight / this.videoWidth;
|
||
}
|
||
|
||
// #ifdef H5
|
||
style += 'padding-top: ' + (ratio * 100) + '%;';
|
||
// #endif
|
||
|
||
// #ifdef MP-WEIXIN
|
||
style += 'padding-top: ' + (ratio * 100) + '%;';
|
||
// #endif
|
||
|
||
// #ifdef MP-HARMONY
|
||
style += 'width: 100%;';
|
||
style += 'height: ' + (this.windowWidth * ratio) + 'px;';
|
||
// #endif
|
||
|
||
return style;
|
||
}
|
||
},
|
||
methods: {
|
||
// 初始化视频数据
|
||
initVideoData() {
|
||
this.videoUrl = this.getVideoUrl();
|
||
this.posterUrl = this.getPosterUrl();
|
||
// H5端:预加载视频获取宽高
|
||
// #ifdef H5
|
||
this.preloadVideoForRatio();
|
||
// #endif
|
||
},
|
||
|
||
// 初始化窗口宽度
|
||
initWindowWidth() {
|
||
try {
|
||
const systemInfo = uni.getSystemInfoSync();
|
||
this.windowWidth = systemInfo.windowWidth || 375;
|
||
} catch (e) {
|
||
this.windowWidth = 375;
|
||
}
|
||
},
|
||
|
||
// 获取视频URL
|
||
getVideoUrl() {
|
||
if (!this.value || !this.value.videoUrl) return '';
|
||
const videoUrl = this.value.videoUrl;
|
||
// 如果是完整的http/https链接,直接使用
|
||
if (videoUrl.indexOf('http://') === 0 || videoUrl.indexOf('https://') === 0) {
|
||
return videoUrl;
|
||
}
|
||
// 否则使用$util.img()处理
|
||
return this.$util.img(videoUrl);
|
||
},
|
||
|
||
// 获取封面图URL
|
||
getPosterUrl() {
|
||
if (!this.value || !this.value.imageUrl) return '';
|
||
return this.$util.img(this.value.imageUrl);
|
||
},
|
||
|
||
// H5端:预加载视频获取宽高比例
|
||
preloadVideoForRatio() {
|
||
const videoUrl = this.videoUrl;
|
||
if (!videoUrl) return;
|
||
|
||
const video = document.createElement('video');
|
||
video.preload = 'metadata';
|
||
video.src = videoUrl;
|
||
video.muted = true;
|
||
video.playsInline = true;
|
||
|
||
video.addEventListener('loadedmetadata', () => {
|
||
const width = video.videoWidth;
|
||
const height = video.videoHeight;
|
||
|
||
if (width && height) {
|
||
this.videoWidth = width;
|
||
this.videoHeight = height;
|
||
}
|
||
});
|
||
|
||
video.addEventListener('error', (e) => {
|
||
console.error(this.$lang('components-diy.diy-video.h5PreloadFailed') + ':', e);
|
||
});
|
||
|
||
// 触发加载
|
||
video.load();
|
||
},
|
||
|
||
// 视频加载完成事件(组件内video标签)
|
||
onVideoLoaded(event) {
|
||
let width = 0;
|
||
let height = 0;
|
||
|
||
// #ifdef H5
|
||
if (event && event.target) {
|
||
width = event.target.videoWidth || 0;
|
||
height = event.target.videoHeight || 0;
|
||
}
|
||
// #endif
|
||
|
||
// #ifdef MP-WEIXIN
|
||
if (event && event.detail) {
|
||
width = event.detail.width || 0;
|
||
height = event.detail.height || 0;
|
||
}
|
||
// #endif
|
||
|
||
// #ifdef MP-HARMONY
|
||
if (event && event.detail) {
|
||
width = event.detail.width || 0;
|
||
height = event.detail.height || 0;
|
||
}
|
||
// #endif
|
||
|
||
if (width && height) {
|
||
this.videoWidth = width;
|
||
this.videoHeight = height;
|
||
}
|
||
},
|
||
|
||
// 视频播放事件
|
||
onVideoPlay() {
|
||
},
|
||
|
||
// 视频暂停事件
|
||
onVideoPause() {
|
||
},
|
||
|
||
// 视频错误事件
|
||
onVideoError(event) {
|
||
console.error(this.$lang('components-diy.diy-video.videoLoadFailed') + ':', event);
|
||
},
|
||
|
||
async handlerClick(videoUrl) {
|
||
await this.__$emitEvent({
|
||
eventName: 'video-tap', data: videoUrl, promiseCallback: (event, handler, awaitedResult) => {
|
||
if (!awaitedResult) return;
|
||
}
|
||
})
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
.video-container {
|
||
width: 100%;
|
||
position: relative;
|
||
overflow: hidden;
|
||
background-color: #000;
|
||
}
|
||
|
||
/* 基础样式 */
|
||
.diy-video {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: block;
|
||
}
|
||
|
||
/* H5端样式 */
|
||
/* #ifdef H5 */
|
||
.h5-video {
|
||
width: 100%;
|
||
height: 100%;
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
object-fit: cover;
|
||
}
|
||
/* #endif */
|
||
|
||
/* 微信小程序端样式 */
|
||
/* #ifdef MP-WEIXIN */
|
||
.mp-video {
|
||
width: 100%;
|
||
height: 100%;
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
}
|
||
/* #endif */
|
||
|
||
/* 鸿蒙元服务端样式 */
|
||
/* #ifdef MP-HARMONY */
|
||
.harmony-video {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: block;
|
||
box-sizing: border-box;
|
||
}
|
||
/* #endif */
|
||
</style>
|