296 lines
6.1 KiB
Vue
296 lines
6.1 KiB
Vue
|
|
<template>
|
|||
|
|
<view class="house-gallery">
|
|||
|
|
<!-- 图片轮播 -->
|
|||
|
|
<u-swiper
|
|||
|
|
:list="swiperList"
|
|||
|
|
:current="current"
|
|||
|
|
height="1200rpx"
|
|||
|
|
>
|
|||
|
|
<template #default="{ item, index }">
|
|||
|
|
<view class="slide-item">
|
|||
|
|
<image :src="item.url" mode="aspectFill" class="slide-img" />
|
|||
|
|
|
|||
|
|
<!-- VR 按钮 -->
|
|||
|
|
<view v-if="item.type === 'vr'" class="vr-btn" @click.stop="openVR">
|
|||
|
|
VR
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 视频按钮 -->
|
|||
|
|
<view v-if="item.type === 'video'" class="video-btn" @click.stop="playVideo">
|
|||
|
|
▶
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 图片索引 -->
|
|||
|
|
<view class="slide-index">{{ index + 1 }}/{{ swiperList.length }}</view>
|
|||
|
|
</view>
|
|||
|
|
</template>
|
|||
|
|
</u-swiper>
|
|||
|
|
|
|||
|
|
<!-- 广告遮罩栏 -->
|
|||
|
|
<view v-if="adVisible && adImage" class="ad-mask" @click="onAdClick">
|
|||
|
|
<image :src="adImage" mode="aspectFill" class="ad-img" />
|
|||
|
|
<view class="ad-close" @click.stop="adVisible = false">×</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 底部 Tab -->
|
|||
|
|
<view class="gallery-tab">
|
|||
|
|
<view
|
|||
|
|
class="gallery-tab-item"
|
|||
|
|
v-for="(item, i) in tabs"
|
|||
|
|
:key="i"
|
|||
|
|
:id="'tab-' + i"
|
|||
|
|
:class="{ active: activeTab === i }"
|
|||
|
|
@click="onTabClick(i)"
|
|||
|
|
>
|
|||
|
|
{{ item.label }}
|
|||
|
|
<text v-if="item.count">({{ item.count }})</text>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 滑块动画 -->
|
|||
|
|
<view
|
|||
|
|
class="tab-line"
|
|||
|
|
:style="{ width: lineStyle.width + 'px', left: lineStyle.left + 'px' }"
|
|||
|
|
></view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 视频弹窗 -->
|
|||
|
|
<u-popup v-model="videoVisible" mode="center" border-radius="20">
|
|||
|
|
<video
|
|||
|
|
:src="videoUrl"
|
|||
|
|
autoplay
|
|||
|
|
controls
|
|||
|
|
style="width: 600rpx; height: 400rpx;"
|
|||
|
|
></video>
|
|||
|
|
</u-popup>
|
|||
|
|
</view>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
export default {
|
|||
|
|
name: "AssetGallery",
|
|||
|
|
props: {
|
|||
|
|
vrImage: String,
|
|||
|
|
videoCover: String,
|
|||
|
|
videoUrl: String,
|
|||
|
|
insideImages: Array,
|
|||
|
|
planImages: Array,
|
|||
|
|
adImage: String
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
data() {
|
|||
|
|
return {
|
|||
|
|
current: 0,
|
|||
|
|
videoVisible: false,
|
|||
|
|
adVisible: true,
|
|||
|
|
tabs: [],
|
|||
|
|
indexMap: [],
|
|||
|
|
lineStyle: { width: 0, left: 0 }
|
|||
|
|
};
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
mounted() {
|
|||
|
|
this.$nextTick(() => {
|
|||
|
|
setTimeout(() => this.updateTabLine(), 50);
|
|||
|
|
});
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
watch: {
|
|||
|
|
activeTab() {
|
|||
|
|
this.$nextTick(() => this.updateTabLine());
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
computed: {
|
|||
|
|
swiperList() {
|
|||
|
|
let list = [];
|
|||
|
|
this.tabs = [];
|
|||
|
|
this.indexMap = [];
|
|||
|
|
let idx = 0;
|
|||
|
|
|
|||
|
|
if (this.vrImage) {
|
|||
|
|
this.tabs.push({ key: "vr", label: "VR", count: 1 });
|
|||
|
|
this.indexMap.push(idx);
|
|||
|
|
list.push({ type: "vr", url: this.vrImage });
|
|||
|
|
idx++;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (this.videoCover) {
|
|||
|
|
this.tabs.push({ key: "video", label: "视频", count: 1 });
|
|||
|
|
this.indexMap.push(idx);
|
|||
|
|
list.push({ type: "video", url: this.videoCover });
|
|||
|
|
idx++;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (this.insideImages?.length > 0) {
|
|||
|
|
this.tabs.push({ key: "inside", label: "内部图", count: this.insideImages.length });
|
|||
|
|
this.indexMap.push(idx);
|
|||
|
|
list.push(...this.insideImages.map((img) => ({ type: "inside", img })));
|
|||
|
|
idx += this.insideImages.length;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (this.planImages?.length > 0) {
|
|||
|
|
this.tabs.push({ key: "plan", label: "平面图", count: this.planImages.length });
|
|||
|
|
this.indexMap.push(idx);
|
|||
|
|
list.push(...this.planImages.map((url) => ({ type: "plan", url })));
|
|||
|
|
idx += this.planImages.length;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return list;
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
activeTab() {
|
|||
|
|
for (let i = 0; i < this.indexMap.length; i++) {
|
|||
|
|
const start = this.indexMap[i];
|
|||
|
|
const end = this.indexMap[i + 1] ?? 99999;
|
|||
|
|
if (this.current >= start && this.current < end) return i;
|
|||
|
|
}
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
methods: {
|
|||
|
|
onAdClick() {
|
|||
|
|
this.$emit("ad-click");
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
onSwiperChange(e) {
|
|||
|
|
this.current = e.detail.current;
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
onTabClick(i) {
|
|||
|
|
this.current = this.indexMap[i];
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
openVR() {
|
|||
|
|
this.$emit("open-vr");
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
playVideo() {
|
|||
|
|
this.videoVisible = true;
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
updateTabLine() {
|
|||
|
|
const index = this.activeTab;
|
|||
|
|
if (this.tabs.length === 0) return;
|
|||
|
|
|
|||
|
|
const id = `#tab-${index}`;
|
|||
|
|
uni.createSelectorQuery()
|
|||
|
|
.in(this)
|
|||
|
|
.select(id)
|
|||
|
|
.boundingClientRect((rect) => {
|
|||
|
|
if (!rect) return;
|
|||
|
|
this.lineStyle = { width: rect.width, left: rect.left };
|
|||
|
|
})
|
|||
|
|
.exec();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style scoped>
|
|||
|
|
.house-gallery {
|
|||
|
|
width: 100%;
|
|||
|
|
position: relative;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 轮播 */
|
|||
|
|
.slide-item {
|
|||
|
|
width: 100%;
|
|||
|
|
height: 1200rpx;
|
|||
|
|
position: relative;
|
|||
|
|
}
|
|||
|
|
.slide-img {
|
|||
|
|
width: 100%;
|
|||
|
|
height: 100%;
|
|||
|
|
border-radius: 0;
|
|||
|
|
}
|
|||
|
|
.vr-btn,
|
|||
|
|
.video-btn {
|
|||
|
|
position: absolute;
|
|||
|
|
bottom: 40rpx;
|
|||
|
|
right: 40rpx;
|
|||
|
|
width: 100rpx;
|
|||
|
|
height: 100rpx;
|
|||
|
|
border-radius: 50%;
|
|||
|
|
background: rgba(0, 0, 0, 0.6);
|
|||
|
|
color: #fff;
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: center;
|
|||
|
|
align-items: center;
|
|||
|
|
font-size: 30rpx;
|
|||
|
|
}
|
|||
|
|
.video-btn {
|
|||
|
|
font-size: 50rpx;
|
|||
|
|
}
|
|||
|
|
.slide-index {
|
|||
|
|
position: absolute;
|
|||
|
|
bottom: 20rpx;
|
|||
|
|
right: 20rpx;
|
|||
|
|
padding: 4rpx 8rpx;
|
|||
|
|
background: rgba(0,0,0,0.5);
|
|||
|
|
color: #fff;
|
|||
|
|
font-size: 24rpx;
|
|||
|
|
border-radius: 10rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 广告遮罩 */
|
|||
|
|
.ad-mask {
|
|||
|
|
position: absolute;
|
|||
|
|
bottom: 0;
|
|||
|
|
left: 0;
|
|||
|
|
width: 100%;
|
|||
|
|
height: 120rpx;
|
|||
|
|
background: rgba(0,0,0,0.35);
|
|||
|
|
padding: 0 20rpx;
|
|||
|
|
z-index: 9;
|
|||
|
|
}
|
|||
|
|
.ad-img {
|
|||
|
|
width: 100%;
|
|||
|
|
height: 100%;
|
|||
|
|
border-radius: 12rpx;
|
|||
|
|
}
|
|||
|
|
.ad-close {
|
|||
|
|
position: absolute;
|
|||
|
|
right: 20rpx;
|
|||
|
|
top: 20rpx;
|
|||
|
|
width: 40rpx;
|
|||
|
|
height: 40rpx;
|
|||
|
|
border-radius: 50%;
|
|||
|
|
background: rgba(0,0,0,0.55);
|
|||
|
|
color: #fff;
|
|||
|
|
text-align: center;
|
|||
|
|
line-height: 40rpx;
|
|||
|
|
font-size: 30rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* Tab bar */
|
|||
|
|
.gallery-tab {
|
|||
|
|
position: absolute;
|
|||
|
|
bottom: 0;
|
|||
|
|
width: 100%;
|
|||
|
|
display: flex;
|
|||
|
|
background: rgba(255,255,255,0.9);
|
|||
|
|
border-top: 1rpx solid #eee;
|
|||
|
|
height: 90rpx;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: space-around;
|
|||
|
|
z-index: 10;
|
|||
|
|
}
|
|||
|
|
.gallery-tab-item {
|
|||
|
|
padding: 20rpx 0;
|
|||
|
|
font-size: 28rpx;
|
|||
|
|
color: #666;
|
|||
|
|
}
|
|||
|
|
.gallery-tab-item.active {
|
|||
|
|
color: #2979ff;
|
|||
|
|
font-weight: bold;
|
|||
|
|
}
|
|||
|
|
.tab-line {
|
|||
|
|
position: absolute;
|
|||
|
|
bottom: 0;
|
|||
|
|
height: 4rpx;
|
|||
|
|
background: #2979ff;
|
|||
|
|
transition: all 0.25s ease;
|
|||
|
|
}
|
|||
|
|
</style>
|