视频组件:vue3-video-play。
用的是vant。本来用的是vant的图片预览组件进行改造的,以便预览图片和视频,后来发现体验太差,于是自己写了一套demo。
主要注意点就是切换的时候要销毁视频,使其重新加载,以免卡顿。
注:右上角还需要一个关闭按钮,有需要的自己添加吧,方法有:webCloseMedia,页面样式没写
<script setup>
import { ref, computed, reactive} from 'vue';
import 'vue3-video-play/dist/style.css';
import { videoPlay } from 'vue3-video-play';
const emit = defineEmits(['update:showPreview']);
const props = defineProps({
images: { // 文件数组,[地址一,地址二,地址三...]
type: Array,
required: true
},
startPosition: {// 从第几个开始
type: Number,
default: () => { return 0; }
},
showPreview: {
type: Boolean,
required: true
}
});
const _showPreview = computed({
get() {
return props.showPreview;
},
set(val) {
emit('update:showPreview', val);
}
});
const currentIndex = ref(props.startPosition);// 当前显示第几张
const showVideodom = ref(true);//是否显示视频
// 播放器配置
const options = reactive({
width: '100%', //播放器高度
height: '100%', //播放器高度
// fullScreen: true,//网页全屏
controlBtns: [
'fullScreen',//全屏按钮
]
});
/**********************滑动方法配置 ***************************/
const startX = ref(0);
const startY = ref(0);
const endX = ref(0);
const endY = ref(0);
const dValueX = ref(0);
const dValueY = ref(0);
const translateX = ref(0);
const horizontalMoved = ref(false);
const verticalMoved = ref(false);
const onTouchStart = (e) => {
startX.value = e.targetTouches[0].pageX; startY.value = e.targetTouches[0].pageY;
};
const onTouchMove = (e) => {
endX.value = e.targetTouches[0].pageX; endY.value = e.targetTouches[0].pageY;
dValueX.value = Math.abs(startX.value - endX.value); dValueY.value = Math.abs(startY.value - endY.value);
const stopRange = window.screen.width - window.screen.width / 3.5;
if (dValueX.value > dValueY.value) {
if (verticalMoved.value) { e.preventDefault(); return; }
else horizontalMoved.value = true;
if (dValueX.value < stopRange) {
if (startX.value > endX.value) {
if (!props.leftDisabled)
translateX.value = dValueX.value * -1;
} else {
if (!props.rightDisabled) translateX.value = dValueX.value;
}
} e.preventDefault();
} else { if (horizontalMoved.value) e.preventDefault(); else verticalMoved.value = true; }
};
const onTouchEnd = (e) => {
const range = window.screen.width / 3;
if (horizontalMoved.value) {
if (dValueX.value > range) {
if (startX.value > endX.value) {
if (!props.leftDisabled) handleChange('left');
} else if (startX.value < endX.value) {
if (!props.rightDisabled) handleChange('right');
}
}
}
horizontalMoved.value = false;
verticalMoved.value = false;
translateX.value = 0;
startX.value = endX.value = 0;
startY.value = endY.value = 0;
};
/**********************end 滑动方法配置 ***************************/
// 右上角关闭按钮事件
const webCloseMedia = () => {
emit('update:showPreview', false);
};
/**
* @description: 滑动使用的方法
* @param {String} value left:左滑 right:右滑
*/
const handleChange = (value) => {
const len = props.images.length;
// 只有一个文件的时候不做反应
if (len === 1) {
return false;
}
showVideodom.value = false;// 模板中用v-if来销毁和展示视频组件
if ('left' === value) {
if (currentIndex.value + 1 === len) {
currentIndex.value = 0;
} else {
++currentIndex.value;
}
} else if ('right' === value) {
if (currentIndex.value === 0) {
currentIndex.value = len - 1;
} else {
--currentIndex.value;
}
}
setTimeout(() => {
showVideodom.value = true;
}, 200);
};
</script>
<template>
<van-overlay
v-model:show="_showPreview" :custom-style="{ background: 'rgba(0,0,0,1)!important' }"
lazy-render :lock-scroll="false"
>
<div
v-if="showVideodom" class="pre-style" @touchstart="onTouchStart" @touchmove="onTouchMove"
@touchend="onTouchEnd"
>
<!-- 我这里只判断了mp4 mov MOV 格式 -->
<videoPlay
v-if="images[currentIndex].endsWith('mp4') || images[currentIndex].toLocaleLowerCase().endsWith('mov')"
v-model:show="_showPreview" :src="images[currentIndex]" autoplay v-bind="options"
/>
<img v-else :src="images[currentIndex]" style="width: 100%;height: 100%;">
</div>
</van-overlay>
</template>
<style lang="less" scoped>
.pre-style {
width: 100%;
height: 100%;
}
</style>