<template>
|
<view :class="[Visible ? 'usable-popup album_open' : 'usable-popup album_close', theme() || '']" :data-theme='theme()'>
|
<view class="popup-bg" @click="closePopup(null)"></view>
|
<view class="main pt30" v-on:click.stop>
|
<view class="popup-title d-s-c pb30 pr border-b-e">
|
<view class="title f28" :class="{'active':file_type=='image'}" @click="changeFileType('image')">活动照片</view>
|
<view class="title f28" :class="{'active':file_type=='video'}" @click="changeFileType('video')">活动视频</view>
|
<view class="iconfont icon-guanbi" @click="closePopup(null)"></view>
|
</view>
|
<scroll-view scroll-y="true" class="scroll-Y" :style="'height:' + scrollviewHigh + 'px;'" :show-scrollbar="false" @scroll="handleScroll" lower-threshold="50" @scrolltolower="scrolltolowerFunc">
|
<!-- 图片 -->
|
<view class="album-box d-s-s f-w" v-if="file_type=='image'">
|
<view class="album-item" v-for="(item, index) in listData" :key="index" @click="previewImage(index)">
|
<image class="image" :src="item.file_path" mode="aspectFill" lazy-load></image>
|
</view>
|
</view>
|
<!-- 视频 -->
|
<view class="album-box album-video" v-else>
|
<view class="video-item" :id="'videoItem' + item.file_id" v-for="(item, index) in listData" :key="item.file_id">
|
<video
|
:id="'video' + item.file_id"
|
class="video radius24"
|
:src="item.file_path"
|
:controls="true"
|
:enable-progress-gesture="true"
|
object-fit="cover"
|
@play="onVideoPlay(item.file_id)"
|
@pause="onVideoPause"
|
@ended="onVideoEnded"
|
></video>
|
</view>
|
</view>
|
<!-- 没有记录 -->
|
<view class="none-data-box" v-if="listData.length==0">
|
<image :src="remoteImg('no_thing')" mode="widthFix"></image>
|
<text>暂无数据</text>
|
</view>
|
<uni-load-more v-else :loadingType="loadingType"></uni-load-more>
|
</scroll-view>
|
</view>
|
<!-- 图片预览 -->
|
<imagePreview ref="image_preview" :show="showPreview" :images="previewImages" @close="closePreview" @download="handleDownload"></imagePreview>
|
</view>
|
</template>
|
|
<script>
|
import uniLoadMore from '@/components/uni-load-more.vue';
|
import imagePreview from './imagePreview.vue';
|
export default {
|
components: {
|
uniLoadMore,
|
imagePreview, // 图片预览
|
},
|
data() {
|
return {
|
/*手机高度*/
|
phoneHeight: 0,
|
/*可滚动视图区域高度*/
|
scrollviewHigh: 0,
|
/*是否可见*/
|
Visible: false,
|
listData: [],
|
file_type: 'image',
|
/*最后一页码数*/
|
last_page: 0,
|
/*当前页面*/
|
page: 1,
|
/*每页条数*/
|
list_rows: 10,
|
/*有没有更多*/
|
no_more: false,
|
/*是否正在加载*/
|
loading: true,
|
previewIndex: 0, // 当前预览的图片索引
|
previewImages: [],
|
showPreview: false, // 是否显示预览
|
// 视频相关
|
currentPlayId: null, // 当前正在播放的视频id
|
scrollTimer: null, // 防抖计时器
|
lastScrollTop: 0, // 记录上次滚动位置
|
};
|
},
|
props: ['isOpenAlbum', 'activity_id'],
|
computed: {
|
/*加载中状态*/
|
loadingType() {
|
if (this.loading) {
|
return 1;
|
} else {
|
if (this.listData.length != 0 && this.no_more) {
|
return 2;
|
} else {
|
return 0;
|
}
|
}
|
}
|
},
|
onLoad() {},
|
mounted() {
|
this.init();
|
this.getData();
|
},
|
watch: {
|
isOpenAlbum: function(n, o) {
|
if (n != o) {
|
this.Visible = n;
|
}
|
}
|
},
|
created() {
|
|
},
|
// 页面卸载时清除定时器
|
onUnload() {
|
if (this.scrollTimer) {
|
clearTimeout(this.scrollTimer);
|
}
|
},
|
methods: {
|
/*初始化*/
|
init() {
|
let self = this;
|
uni.getSystemInfo({
|
success(res) {
|
self.phoneHeight = res.windowHeight;
|
self.scrollviewHigh = self.phoneHeight * 0.8
|
}
|
});
|
},
|
|
/*初始化列表数据*/
|
initData() {
|
this.page = 1;
|
this.last_page = 0;
|
this.listData = [];
|
},
|
|
/*获取数据*/
|
getData() {
|
let self = this;
|
self.loading = true;
|
self._get(
|
'branch.activity/fileLists', {
|
activity_id: self.activity_id,
|
file_type: self.file_type,
|
page: self.page,
|
list_rows: self.list_rows,
|
// pay_source: self.getPlatform(),
|
},
|
function(res) {
|
self.loading = false;
|
self.listData = self.listData.concat(res.data.list.data);
|
self.last_page = res.data.list.last_page;
|
if (res.data.list.last_page <= 1) {
|
self.no_more = true;
|
} else {
|
self.no_more = false;
|
}
|
}
|
);
|
},
|
|
// 防抖函数
|
debounce(func, wait) {
|
return (...args) => {
|
clearTimeout(this.scrollTimer)
|
this.scrollTimer = setTimeout(() => {
|
func.apply(this, args)
|
}, wait)
|
}
|
},
|
|
// 滚动处理函数 - 使用防抖优化
|
handleScroll(e) {
|
// 立即更新滚动位置,用于判断滚动方向
|
const scrollTop = e.detail.scrollTop
|
const scrollDirection = scrollTop > this.lastScrollTop ? 'down' : 'up'
|
|
// 只在向下滚动时检查视频可见性
|
if (scrollDirection === 'down') {
|
// 使用防抖处理滚动检查
|
this.debounceScrollCheck(scrollTop)
|
}
|
|
// 保存当前滚动位置
|
this.lastScrollTop = scrollTop
|
},
|
|
// 防抖后的滚动检查
|
debounceScrollCheck: function() {
|
// 防抖包装,实际执行的是这个函数
|
return this.debounce(function(scrollTop) {
|
// 如果没有正在播放的视频,直接返回
|
if (!this.currentPlayId) return
|
|
// 获取当前播放视频的位置
|
this.checkVideoVisibility(this.currentPlayId)
|
}, 150) // 150ms延迟,可根据需要调整
|
},
|
|
// 检查视频可见性
|
checkVideoVisibility(videoId) {
|
const query = uni.createSelectorQuery().in(this)
|
query.select('#videoItem' + videoId).boundingClientRect()
|
query.exec(res => {
|
if (res[0]) {
|
const rect = res[0]
|
const windowHeight = uni.getSystemInfoSync().windowHeight
|
|
// 判断视频是否完全滑出可视区域
|
// 这里可以调整阈值,例如当视频顶部距离屏幕底部超过一定距离时暂停
|
if (rect.bottom < -50 || rect.top > windowHeight + 50) {
|
this.pauseVideo(videoId)
|
}
|
}
|
})
|
},
|
|
// 播放视频
|
playVideo(id) {
|
// 如果之前有播放的视频,先停止
|
if (this.currentPlayId && this.currentPlayId !== id) {
|
this.pauseVideo(this.currentPlayId)
|
}
|
|
this.currentPlayId = id
|
this.$nextTick(() => {
|
const videoContext = uni.createVideoContext('video' + id, this)
|
videoContext.play()
|
})
|
},
|
|
// 暂停视频
|
pauseVideo(id) {
|
const videoContext = uni.createVideoContext('video' + id, this)
|
videoContext.pause()
|
// 如果暂停的是当前播放的视频,清空currentPlayId
|
if (this.currentPlayId === id) {
|
this.currentPlayId = null
|
}
|
},
|
|
onVideoPlay(id) {
|
console.log('视频开始播放:', id)
|
this.playVideo(id);
|
// this.currentPlayId = id
|
},
|
|
onVideoPause() {
|
console.log('视频暂停')
|
},
|
|
onVideoEnded() {
|
console.log('视频播放结束')
|
this.currentPlayId = null
|
},
|
|
/*可滚动视图区域到底触发*/
|
scrolltolowerFunc() {
|
let self = this;
|
if (self.no_more) {
|
return;
|
}
|
self.page++;
|
if (self.page <= self.last_page) {
|
self.getData();
|
} else {
|
self.no_more = true;
|
}
|
},
|
|
changeFileType(e) {
|
this.file_type = e;
|
this.initData();
|
this.getData();
|
},
|
|
// 显示预览
|
previewImage(e) {
|
this.previewIndex = e;
|
this.previewImages = this.listData.map(item => {
|
return {
|
file_id: item.file_id,
|
file_path: item.file_path,
|
file_type: item.file_type,
|
is_original: item.is_original,
|
};
|
});
|
this.showPreview = true;
|
this.$refs.image_preview.current = e;
|
},
|
|
// 关闭预览
|
closePreview() {
|
this.showPreview = false;
|
},
|
|
/*关闭弹窗*/
|
closePopup(e) {
|
this.$emit('close', e);
|
}
|
}
|
};
|
</script>
|
|
<style lang="scss" scoped>
|
.usable-popup .popup-bg {
|
position: fixed;
|
top: 0;
|
right: 0;
|
bottom: 0;
|
left: 0;
|
background: rgba(0, 0, 0, 0.6);
|
z-index: 110;
|
}
|
|
.usable-popup .main {
|
position: fixed;
|
width: 100%;
|
bottom: 0;
|
min-height: 200rpx;
|
background-color: #ffffff;
|
transform: translate3d(0, 1380rpx, 0);
|
transition: transform 0.2s cubic-bezier(0, 0, 0.25, 1);
|
bottom: env(safe-area-inset-bottom);
|
z-index: 110;
|
border-radius: 30rpx 30rpx 0 0;
|
}
|
|
.usable-popup.album_open .main {
|
transform: translate3d(0, 0, 0);
|
}
|
|
.usable-popup.album_close .popup-bg {
|
display: none;
|
}
|
|
.popup-title {
|
.iconfont {
|
position: absolute;
|
right: 30rpx;
|
top: 10rpx;
|
color: #999999;
|
}
|
.title {
|
margin-left: 30rpx;
|
background-color: #eee;
|
border-radius: 60rpx;
|
padding: 10rpx 30rpx;
|
&.active {
|
color: #ffffff;
|
@include background_color('background_color');
|
}
|
}
|
}
|
|
.album-box {
|
padding: 15rpx 15rpx;
|
.album-item {
|
width: 50%;
|
padding: 15rpx;
|
box-sizing: border-box;
|
.image {
|
width: 100%;
|
height: 220rpx;
|
border-radius: 12rpx;
|
}
|
}
|
}
|
|
.album-video {
|
.video-item {
|
padding: 15rpx;
|
.video {
|
width: 100%;
|
height: 380rpx;
|
}
|
}
|
}
|
|
</style>
|