提交 cb2cf54d 作者: 方治民

feat: 新增 ThumbnailPreview 组件,用于预览图片 + 视频

上级 5ad81c48
<script lang="ts" setup>
import type { PropType } from 'vue'
import { nanoid } from 'nanoid'
import { isImage, isVideo, getPoster } from './utils'
type URLs = { url: string }[]
const props = defineProps({
width: {
type: [String, Number],
default: '96',
},
height: {
type: [String, Number],
default: '96',
},
mode: {
type: String,
default: 'aspectFit',
},
assets: {
type: Array as PropType<Recordable & URLs>,
},
})
// 生成预览容器高度
const containerHeight = `${props.height}rpx`
// 分离图片和视频资源地址
const images = computed(() => props.assets.filter((item) => isImage(item.url)))
const videos = computed(() => props.assets.filter((item) => isVideo(item.url)))
// 预览图片
const preview = (index: number) => {
uni.previewImage({
urls: images.value.map((item) => item.url),
current: index,
})
}
// 初始化视频组件配置
const videoId = nanoid()
const videoContext = ref()
const playVideoSrc = ref()
// 播放视频
const play = (index: number) => {
playVideoSrc.value = videos.value[index].url
videoContext.value?.requestFullScreen()
videoContext.value?.play()
}
const videoFullScreenChange = (e: any) => {
// 非全屏状态下停止播放
if (!e.detail.fullScreen) {
videoContext.value?.stop()
}
}
onMounted(() => {
// 初始化视频组件上下文对象
videoContext.value = uni.createVideoContext(videoId)
})
</script>
<template>
<view class="preview-wrap">
<!-- 视频预览 -->
<fui-lazyload
class="preview-video"
:mode="props.mode"
v-for="(item, index) in videos"
:key="item.url"
:src="getPoster(item.url)"
:width="props.width"
:height="props.height"
:radius="10"
@tap="play(index)"
>
<view class="icon-wrap" :style="{ width: props.width, height: props.height }">
<fui-icon class="video-play-icon" name="suspend" size="40" color="#fff" />
</view>
</fui-lazyload>
<!-- 图片预览 -->
<fui-lazyload
class="preview-image"
:mode="props.mode"
v-for="(item, index) in images"
:key="item.url"
:src="getPoster(item.url)"
:width="props.width"
:height="props.height"
:radius="10"
@tap="preview(index)"
/>
<!-- 视频 -->
<video
:id="videoId"
:src="playVideoSrc"
class="video"
autoplay
controls
@fullscreenchange="videoFullScreenChange"
></video>
</view>
</template>
<style lang="less" scoped>
.preview-wrap {
display: flex;
flex-wrap: wrap;
margin: -10rpx;
.preview-image,
.preview-video {
margin: 10rpx !important;
position: relative;
:deep(.fui-lazyload__img) {
height: v-bind(containerHeight) !important;
}
.icon-wrap {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
border-radius: 10rpx;
.video-play-icon {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
}
.video {
position: absolute;
top: -999999px;
}
}
</style>
export type FileType = 'image' | 'video' | 'audio'
export function isImage(url: string) {
return /\.(png|jpe?g|gif|svg)(\?.*)?$/i.test(url)
}
export function isVideo(url: string) {
return /\.(mp4|m3u8)(\?.*)?$/i.test(url)
}
export function getPoster(url: string) {
if (!isVideo(url)) {
return url
}
return url + '.jpg'
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论