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.
 
 
 
 

994 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/20250804/1830fb1be82f44d6405d35cebd70b78a.gif'
)
"
: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/20250806/a0663a49a6037da67fa5cd897311765e.png'
)
"
:lazy-load="true"
mode="aspectFit"
>
</image>
</view>
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container" style="background-color: #efefef">
<template v-if="loadedPages[1]">
<image
v-show="shouldShowContent(1)"
class="bg-image"
:src="
showImg(
'/uploads/20250801/9bdda955f86ad07b745c3095431ca38e.png'
)
"
:lazy-load="true"
mode="aspectFit"
></image>
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[2]">
<image
@click="nextIndex"
v-show="shouldShowContent(2)"
class="bg-image"
:src="
showImg(
'/uploads/20250804/5e9bdcff219f92fd6bc33444d670b807.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: 590rpx"
:src="
showImg(
'/uploads/20250804/071658650e402f55ac2cbf87cf7ce0e5.png'
)
"
mode="widthFix"
@click="showPopupImage(1)"
></image>
<image
style="width: 590rpx; margin-top: 175rpx"
:src="
showImg(
'/uploads/20250804/418af80ee3c09def1768da53b5c8760a.png'
)
"
mode="widthFix"
@click="showPopupImage(2)"
></image>
<image
style="width: 590rpx; margin-top: 160rpx"
:src="
showImg(
'/uploads/20250804/c82764802f8022eb14d40d222a29fcd3.png'
)
"
mode="widthFix"
@click="showPopupImage(3)"
></image>
<image
style="width: 590rpx; margin-top: 160rpx"
:src="
showImg(
'/uploads/20250804/da9b9a28af4dcaac683d9a5af53a7667.png'
)
"
mode="widthFix"
@click="showPopupImage(4)"
></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/20250804/d2a7c31d03d3ade96ae6a9abefb78869.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>
<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"
v-if="currentTagImg == 1"
:src="
showImg('/uploads/20250802/a2245bbeba155410fd765439a18774f7.png')
"
mode="widthFix"
></image>
<image
class="popup-image"
v-if="currentTagImg == 2"
:src="
showImg('/uploads/20250802/6a740ec7fc10dd0f6ddcc65faca3b3c8.png')
"
mode="widthFix"
></image>
<image
class="popup-image"
v-if="currentTagImg == 3"
:src="
showImg('/uploads/20250802/4e89bbb52de311cfae7ef1b59ee2f2c8.png')
"
mode="widthFix"
></image>
<image
v-if="currentTagImg == 4"
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 {
currentTagImg: 1,
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: "序章",
targetIndex: 0,
},
{
text: "第一章猪的起源",
targetIndex: 4,
},
{
text: "第二章驯为良伴",
targetIndex: 5,
},
{
text: "第三章身份之谜",
targetIndex: 6,
},
{
text: "第四章 东方之猪",
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: {
nextIndex() {
console.log("---");
this.currentIndex = this.currentIndex + 1;
},
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(index) {
this.showImagePopup = true;
this.currentTagImg = index;
},
hidePopupImage() {
this.showImagePopup = false;
},
},
mounted() {
this.titleHeight = uni.getStorageSync("titleHeight");
const app = getApp();
app.updateMusicSrc("https://static.ticket.sz-trip.com/epicSoul/bgm.mp3");
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」阅读体 issue04",
mpId: "wx8954209bb3ad489e",
path: "/pig/home/home",
imageUrl:
"https://epic.js-dyyj.com/uploads/20250805/4a90a8f7de19b0c465ff30e1b8e0c35c.png",
};
},
onShareTimeline() {
return {
title: "猪的美学进化史|「Epic Soul」阅读体 issue04",
path: "/pig/home/home",
imageUrl:
"https://epic.js-dyyj.com/uploads/20250805/4a90a8f7de19b0c465ff30e1b8e0c35c.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: 650rpx;
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: rgba(255, 255, 255, 0.95);
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: #333;
opacity: 0.7;
font-size: 28rpx;
}
}
.item-active {
background-color: rgba(0, 0, 0, 0.1);
}
.nav-item .active {
color: #333;
opacity: 1;
}
.chapter-text {
display: flex;
flex-direction: column;
align-items: center;
line-height: 1.3;
}
.chapter-title {
color: #333;
opacity: 0.7;
font-size: 24rpx;
}
.chapter-number {
color: #333;
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>