You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

1005 lines
22 KiB

<template>
<view>
<swiper
class="main-swiper"
:vertical="true"
:current="currentIndex"
@change="handleSwiperChange"
:duration="300"
:style="{ height: `100vh` }"
>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[0]">
<image
v-show="shouldShowContent(0)"
class="bg-image"
:src="
showImg(
'/uploads/20250801/fe2e7779e0c438ea36308390cba55ef1.png'
)
"
:lazy-load="true"
mode="aspectFill"
></image>
<view v-show="shouldShowContent(0)" class="content-layer">
<image
class="layer-img"
:class="{
'blur-to-clear': animationStates[0],
hidden: !animationStates[0],
}"
:src="
showImg(
'/uploads/20250801/4059157496ea8a1ce3ef9610a63858a7.png'
)
"
:lazy-load="true"
mode="aspectFit"
>
</image>
</view>
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[1]">
<image
v-show="shouldShowContent(1)"
class="bg-image"
:src="
showImg(
'/uploads/20250801/9bdda955f86ad07b745c3095431ca38e.png'
)
"
:lazy-load="true"
mode="aspectFill"
></image>
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[2]">
<image
v-show="shouldShowContent(2)"
style="
position: absolute;
width: 32.67%;
height: 4.2%;
top: 33.73%;
left: 16%;
z-index: 9999;
"
:src="
showImg(
'/uploads/20250801/01f02fc938da66f4da5019da6f98a664.png'
)
"
:lazy-load="true"
mode="aspectFill"
></image>
<image
v-show="shouldShowContent(2)"
class="bg-image"
:src="
showImg(
'/uploads/20250801/d4efcdff86a15f7feb28d3662ee055ca.png'
)
"
:lazy-load="true"
mode="aspectFill"
></image>
</template>
</view>
</swiper-item>
<swiper-item>
<template v-if="loadedPages[3]">
<view class="loadedPages-three">
<view
class=""
style="width: 750rpx; height: 1400rpx; position: relative"
>
<image
style="width: 100%; height: 100%"
:src="
showImg(
'/uploads/20250802/95daa339dce3ccd25acfc1e0fa031a01.png'
)
"
mode="widthFix"
></image>
<view
class="loadedPages-three-content"
style="position: absolute; top: 375rpx; left: 100rpx"
>
<image
style="width: 286rpx"
:src="
showImg(
'/uploads/20250802/4eaea258b31e3d7a62a9b2511465261f.png'
)
"
mode="widthFix"
@click="showPopupImage"
></image>
</view>
</view>
</view>
</template>
</swiper-item>
<swiper-item>
<view class="page-container">
<image
style="width: 100%; height: 100%"
:src="
showImg('/uploads/20250802/2e287bc4a678a5b47565556d23c31f4f.png')
"
mode="aspectFill"
></image>
<image
@click="goChapter"
style="
width: 137rpx;
height: 108rpx;
position: absolute;
bottom: 125rpx;
left: 307rpx;
"
:src="
showImg('/uploads/20250802/165e072a1537b0fab14c6ec2f42e7974.png')
"
mode="aspectFill"
></image>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<image
style="width: 100%; height: 100%"
:src="
showImg('/uploads/20250802/dee49f1aa510d85c368aafc889e24cc0.png')
"
mode="aspectFill"
></image>
<image
@click="goChapter"
style="
width: 137rpx;
height: 108rpx;
position: absolute;
bottom: 125rpx;
left: 307rpx;
"
:src="
showImg('/uploads/20250802/165e072a1537b0fab14c6ec2f42e7974.png')
"
mode="aspectFill"
></image>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<image
style="width: 100%; height: 100%"
:src="
showImg('/uploads/20250802/c25deec8a6e4f84c8229718312c6ff02.png')
"
mode="aspectFill"
></image>
<image
@click="goChapter"
style="
width: 137rpx;
height: 108rpx;
position: absolute;
bottom: 125rpx;
left: 307rpx;
"
:src="
showImg('/uploads/20250802/165e072a1537b0fab14c6ec2f42e7974.png')
"
mode="aspectFill"
></image>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<image
style="width: 100%; height: 100%"
:src="
showImg('/uploads/20250802/c21b01fea9610f8069a768f03a173b66.png')
"
mode="aspectFill"
></image>
<image
@click="goChapter"
style="
width: 137rpx;
height: 108rpx;
position: absolute;
bottom: 125rpx;
left: 307rpx;
"
:src="
showImg('/uploads/20250802/165e072a1537b0fab14c6ec2f42e7974.png')
"
mode="aspectFill"
></image>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<image
style="width: 100%; height: 100%"
:src="
showImg('/uploads/20250802/bb670192ddcc2bf81aad4eb030ca6cbf.png')
"
mode="aspectFill"
></image>
</view>
</swiper-item>
<swiper-item>
<view class="page-container home-page">
<template>
<image
class="bg-image"
src="https://static.ticket.sz-trip.com/epicSoul/footers.png"
:lazy-load="true"
mode="aspectFill"
></image>
<image
class="qrCode-image"
src="https://static.ticket.sz-trip.com/epicSoul/qrCode.png"
:lazy-load="true"
mode="widthFix"
:show-menu-by-longpress="true"
></image>
</template>
</view>
</swiper-item>
</swiper>
<view class="overlay" v-if="showMenu" @click="closeMenu"></view>
<view class="fixed-nav" :class="{ hidden: showMenu }" @click="showNavMenu">
<image
class="nav-icon"
:class="{ rotated: iconRotated, 'bounce-back': iconBounceBack }"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/nav-icon.png"
mode="aspectFill"
></image>
</view>
<view class="nav-menu" :class="{ show: showMenu }">
<view
class="nav-item"
:class="{ 'item-active': isItemActive(item) }"
v-for="item in menuItems"
:key="item.targetIndex"
@click="() => jumpToPage(item.targetIndex)"
>
<view v-if="item.text.includes('#Chapter')" class="chapter-text">
<text class="chapter-title">#Chapter</text>
<text :class="{ active: isItemActive(item) }" class="chapter-number">
{{ item.text.replace("#Chapter", "") }}
</text>
</view>
<text v-else :class="{ active: isItemActive(item) }">{{
item.text
}}</text>
</view>
</view>
<!-- <BuyPeaches /> -->
<!-- <BackgroundMusic /> -->
<MusicControl />
<!-- 图片弹窗 -->
<view
class="image-popup-overlay"
v-if="showImagePopup"
@click="hidePopupImage"
>
<view class="image-popup-container" @click.stop>
<image
class="popup-image"
:src="
showImg('/uploads/20250802/a2245bbeba155410fd765439a18774f7.png')
"
mode="widthFix"
></image>
<image
class="popup-image"
:src="
showImg('/uploads/20250802/6a740ec7fc10dd0f6ddcc65faca3b3c8.png')
"
mode="widthFix"
></image>
<image
class="popup-image"
:src="
showImg('/uploads/20250802/4e89bbb52de311cfae7ef1b59ee2f2c8.png')
"
mode="widthFix"
></image>
<image
class="popup-image"
:src="
showImg('/uploads/20250802/76b84f3dd91bfebaec35aadc086410b8.png')
"
mode="widthFix"
></image>
<view class="close-btn" @click="hidePopupImage">×</view>
</view>
</view>
</view>
</template>
<script>
import BuyPeaches from "@/components/BuyPeaches.vue";
import messagePop from "@/components/messagePop.vue";
// import BackgroundMusic from '@/components/BackgroundMusic.vue';
import messageBoard from "@/components/messageBoard.vue";
import MusicControl from "@/components/MusicControl.vue";
import TitleHeader from "@/components/TitleHeader.vue";
export default {
components: {
BuyPeaches,
messagePop,
// BackgroundMusic,
messageBoard,
MusicControl,
TitleHeader,
},
data() {
return {
currentIndex: 0,
loadedPages: {
0: false,
1: false,
2: false,
3: false,
4: false,
5: false,
6: false,
7: false,
8: false,
9: false,
10: false,
},
animationStates: {
0: false,
1: false,
2: false,
3: false,
4: false,
5: false,
6: false,
7: false,
8: false,
9: false,
},
preloadBuffer: 1,
isFirstSwipe: true,
showMenu: false,
iconRotated: false,
iconBounceBack: false,
showImagePopup: false,
menuItems: [
{
text: "Intro序曲",
targetIndex: 0,
},
{
text: "#Chapter 壹",
targetIndex: 4,
},
{
text: "#Chapter 贰",
targetIndex: 5,
},
{
text: "#Chapter 叁",
targetIndex: 6,
},
{
text: "#Chapter 肆",
targetIndex: 7,
},
// {
// text: "GuestBook",
// targetIndex: 10,
// },
],
chapterPaths: {
4: "/pig/chapter1/chapter1",
5: "/pig/chapter2/chapter2",
6: "/pig/chapter3/chapter3",
7: "/pig/chapter4/chapter4",
},
titleHeight: 0,
};
},
computed: {
shouldShowContent() {
return (index) => {
return Math.abs(index - this.currentIndex) <= this.preloadBuffer;
};
},
},
watch: {
currentIndex(newIndex) {
for (
let i = Math.max(0, newIndex - this.preloadBuffer);
i <= Math.min(10, newIndex + this.preloadBuffer);
i++
) {
this.loadedPages[i] = true;
}
},
},
methods: {
handleSwiperChange(e) {
const newIndex = e.detail.current;
this.currentIndex = newIndex;
this.animationStates[newIndex] = false;
setTimeout(() => {
this.animationStates[newIndex] = true;
}, 50);
return;
if (this.isFirstSwipe && newIndex > 0) {
this.isFirstSwipe = false;
uni.$emit("playBackgroundMusic");
}
},
goChapter() {
const path = this.chapterPaths[this.currentIndex];
uni.navigateTo({
url: path,
});
},
showNavMenu() {
this.iconRotated = true;
setTimeout(() => {
this.showMenu = true;
}, 300);
},
closeMenu() {
this.showMenu = false;
setTimeout(() => {
this.iconBounceBack = true;
this.iconRotated = false;
setTimeout(() => {
this.iconBounceBack = false;
}, 500);
}, 300);
},
jumpToPage(idx) {
const targetIndex = idx;
this.currentIndex = targetIndex;
this.closeMenu();
this.animationStates[targetIndex] = false;
setTimeout(() => {
this.animationStates[targetIndex] = true;
}, 50);
},
isItemActive(item) {
return this.currentIndex === item.targetIndex;
},
showPopupImage() {
this.showImagePopup = true;
},
hidePopupImage() {
this.showImagePopup = false;
},
},
mounted() {
this.titleHeight = uni.getStorageSync("titleHeight");
console.log(this.titleHeight);
const app = getApp();
app.updateMusicSrc(
"https://static.ticket.sz-trip.com/epicSoul/taozi/bg.m4a"
);
app.initBackgroundMusic(); // 初始化背景音乐
uni.$bgMusic.play(); // 播放音乐
for (let i = 0; i <= Math.min(1 + this.preloadBuffer, 6); i++) {
this.loadedPages[i] = true;
}
for (let i = 0; i <= Math.min(1 + this.preloadBuffer, 10); i++) {
this.loadedPages[i] = true;
}
setTimeout(() => {
this.animationStates[this.currentIndex] = true;
}, 50);
},
onUnload() {
uni.$bgMusic.pause(); // 停止音乐
},
onLoad(options) {
if (options && options.targetIndex) {
const targetIndex = parseInt(options.targetIndex);
this.currentIndex = targetIndex;
for (
let i = Math.max(0, targetIndex - this.preloadBuffer);
i <= Math.min(10, targetIndex + this.preloadBuffer);
i++
) {
this.loadedPages[i] = true;
}
this.animationStates[targetIndex] = false;
setTimeout(() => {
this.animationStates[targetIndex] = true;
}, 50);
}
},
// #ifdef MP-WEIXIN
onShareAppMessage() {
return {
title: "三个桃子·时间里的约定|「Epic Soul」阅读体 issue01",
mpId: "wx8954209bb3ad489e",
path: "/taozi/home/home",
imageUrl:
"https://static.ticket.sz-trip.com/epicSoul/taozi/home/taoziShare.png",
};
},
onShareTimeline() {
return {
title: "三个桃子·时间里的约定|「Epic Soul」阅读体 issue01",
query: "",
imageUrl:
"https://static.ticket.sz-trip.com/epicSoul/taozi/home/taoziShare.png",
};
},
// #endif
};
</script>
<style lang="scss" scoped>
@font-face {
font-family: "SourceHanSerif-Regular";
src: url(/static/fonts/SourceHanSerifSC-Regular.otf);
}
.main-swiper {
width: 100%;
height: 100vh;
}
.page-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
position: relative;
overflow: hidden;
}
.loadedPages-three {
height: 100%;
position: relative;
background: #efefef;
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
}
.loadedPages-three-content {
height: 100%;
.loadedPages-three-title {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
margin-top: 30rpx;
.txt {
font-size: 24rpx;
color: #333;
font-family: SourceHanSerif-Regular;
display: flex;
flex-direction: column;
align-items: center;
text {
display: block;
}
}
.txt:first-child {
margin-left: 30rpx;
}
.txt:last-child {
margin-right: 30rpx;
}
}
.loadedPages-three-center {
position: relative;
.desc {
display: flex;
flex-direction: column;
font-family: SourceHanSerif-Regular;
font-size: 90rpx;
color: #ec4899;
text {
display: block;
}
}
.en-desc {
display: flex;
flex-direction: column;
position: absolute;
top: 50%;
right: 0;
transform: translate(-25%, -50%);
font-size: 24rpx;
font-style: italic;
color: #4b5563;
text {
display: block;
}
}
}
.loadedPages-three-bottom {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 30rpx;
.bottom-img {
width: 400rpx;
height: 120rpx;
}
.bottom-tit {
font-size: 38rpx;
}
.bottom-txt {
font-size: 24rpx;
font-style: italic;
color: #4b5563;
}
}
}
.bg-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.content-layer {
position: relative;
z-index: 2;
width: 100%;
height: 100%;
display: flex;
align-items: center;
flex-direction: column;
}
.content-layer2 {
z-index: 2;
position: absolute;
bottom: 5%;
right: 5%;
}
.layer-img {
width: 541rpx;
height: 100%;
}
.arrow-down {
width: 100rpx;
height: 40rpx;
animation: bounce 1.5s infinite;
}
.layer-icon {
width: 100rpx;
height: 100rpx;
animation: bounce 1.5s infinite;
}
.overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.3);
z-index: 10;
}
.fixed-nav {
width: 80rpx;
height: 80rpx;
background-color: rgb(0 0 0 / 0.7);
border-radius: 10rpx 0 0 10rpx;
position: fixed;
right: 0;
top: 0;
bottom: 0;
margin: auto 0;
display: flex;
align-items: center;
justify-content: center;
z-index: 9;
transition: transform 0.3s ease, opacity 0.3s ease;
}
.fixed-nav.hidden {
transform: translateX(100%);
opacity: 0;
pointer-events: none;
}
.nav-icon {
width: 35rpx;
height: 35rpx;
transition: transform 0.3s ease;
}
.nav-icon.rotated {
transform: rotate(180deg);
}
.nav-icon.bounce-back {
animation: bounceRotation 0.5s ease;
}
@keyframes bounceRotation {
0% {
transform: rotate(180deg);
}
50% {
transform: rotate(-20deg);
}
75% {
transform: rotate(10deg);
}
100% {
transform: rotate(0deg);
}
}
.nav-menu {
position: fixed;
top: 50%;
right: 0;
transform: translate(100%, -50%);
z-index: 11;
background-color: rgb(0 0 0 / 0.5);
border-radius: 16rpx 0 0 16rpx;
box-shadow: -4px 0 15px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease;
}
.nav-menu.show {
transform: translate(0, -50%);
}
.nav-item {
padding: 20rpx;
text-align: center;
text {
color: #fff;
opacity: 0.7;
font-size: 28rpx;
}
}
.item-active {
background-color: rgba(0, 0, 0, 0.718);
}
.nav-item .active {
color: #fff;
opacity: 1;
}
.chapter-text {
display: flex;
flex-direction: column;
align-items: center;
line-height: 1.3;
}
.chapter-title {
color: #fff;
opacity: 0.7;
font-size: 24rpx;
}
.chapter-number {
color: #fff;
opacity: 0.7;
font-size: 28rpx;
margin-top: 8rpx;
}
.item-active .chapter-title,
.item-active .chapter-number.active {
opacity: 1;
}
@keyframes bounce {
0%,
20%,
50%,
80%,
100% {
transform: translateY(0);
}
40% {
transform: translateY(-20rpx);
}
60% {
transform: translateY(-10rpx);
}
}
.blur-to-clear {
animation: blurToClear 1.5s ease-out forwards;
}
@keyframes blurToClear {
0% {
filter: blur(10px);
opacity: 0.3;
}
100% {
filter: blur(0);
opacity: 1;
}
}
.hidden {
opacity: 0;
}
.bounce-in {
animation: bounceIn 1s ease forwards;
}
@keyframes bounceIn {
0% {
opacity: 0;
transform: scale(0.3) translateY(100px);
}
50% {
opacity: 1;
transform: scale(1.05) translateY(-10px);
}
70% {
transform: scale(0.9) translateY(5px);
}
100% {
opacity: 1;
transform: scale(1) translateY(0);
}
}
.fade-slide-up {
animation: fadeSlideUp 1s ease-out forwards;
}
@keyframes fadeSlideUp {
0% {
opacity: 0;
transform: translateY(30px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
.chapterCover-btn {
position: absolute;
left: 50%;
bottom: 10%;
transform: translate(-50%, -50%);
width: 300rpx;
height: 100rpx;
z-index: 2;
}
.qrcode-txt {
width: 30vw;
z-index: 2;
position: fixed;
left: 0;
right: 0;
margin: 100rpx auto 0;
}
.qrcode-txts {
width: 28vw;
z-index: 2;
position: fixed;
left: 0;
right: 0;
margin: 335rpx auto 0;
}
.message-board {
width: 100%;
}
.qrCode-image {
position: absolute;
left: 0;
right: 0;
bottom: 192rpx;
margin: 0 auto;
z-index: 2;
width: 30vw;
}
.image-popup-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.8);
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
}
.image-popup-container {
position: relative;
max-width: 90vw;
max-height: 90vh;
}
.popup-image {
width: 750rpx;
height: 654rpx;
max-width: 100%;
max-height: 100%;
}
.close-btn {
position: absolute;
top: -20rpx;
right: -20rpx;
width: 60rpx;
height: 60rpx;
background-color: rgba(255, 255, 255, 0.9);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 40rpx;
color: #333;
cursor: pointer;
}
</style>