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.

795 lines
18 KiB

3 months ago
<template>
<view>
<TitleHeader />
<swiper class="main-swiper" :vertical="true" :current="currentIndex" @change="handleSwiperChange"
:duration="300" :style="{ height: `calc(100vh - ${titleHeight}px)` }">
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[0]">
<image v-show="shouldShowContent(0)" class="bg-image"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/home/foreword-bg1.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="https://static.ticket.sz-trip.com/epicSoul/taozi/home/foreword-bg1-text.png"
:lazy-load="true" mode="aspectFill">
</image>
<view class="arrow-content">
<image class="arrow-down"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/arrow-icon.png"
:lazy-load="true" mode="aspectFill"></image>
</view>
</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="https://static.ticket.sz-trip.com/epicSoul/taozi/home/prologue1s.png" :lazy-load="true"
mode="aspectFill"></image>
<!-- <view v-show="shouldShowContent(1)" class="content-layer2">
<image class="layer-icon"
:class="{'bounce-in': animationStates[1], 'hidden': !animationStates[1]}"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/home/prologue1-icon.png"
:lazy-load="true" mode="aspectFill">
</image>
</view> -->
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[2]">
<image v-show="shouldShowContent(2)" class="bg-image"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/home/foreword-bg2.gif"
:lazy-load="true" mode="aspectFill"></image>
</template>
</view>
</swiper-item>
<swiper-item>
<template v-if="loadedPages[3]">
<view class="loadedPages-three">
<view class="loadedPages-three-content">
<view class="loadedPages-three-title">
<view class="txt">
DAYUN
</view>
<view class="txt">
<text>IP Art</text>
<text>Exhibition</text>
</view>
<view class="txt">
issue/01
</view>
</view>
<view class="loadedPages-three-center">
<view class="desc">
<text>时间里</text>
<text></text>
<text>约定</text>
</view>
<view class="en-desc">
<text>Agreements</text>
<text>Within</text>
<text>Time</text>
</view>
</view>
<view class="loadedPages-three-bottom"
:class="{'fade-slide-up': animationStates[3], 'hidden': !animationStates[3]}">
<image class="bottom-img"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/home/forewordThree_icon.png"
mode="aspectFill"></image>
<view class="bottom-tit">
三个桃子IP美数展
</view>
<view class="bottom-txt">
Three Peaches IP Art Exhibition
</view>
</view>
</view>
</view>
</template>
</swiper-item>
<swiper-item v-for="index in [4, 5, 6, 7]" :key="index">
<view class="page-container">
<template v-if="loadedPages[index]">
<image v-show="shouldShowContent(index)" class="bg-image"
:src="`https://static.ticket.sz-trip.com/epicSoul/taozi/home/chapterCover${index-3}.png`"
:lazy-load="true" mode="aspectFill"></image>
<image @click="goChapter" class="chapterCover-btn" v-show="shouldShowContent(index)"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/home/toggle.png" :lazy-load="true"
mode="aspectFill"></image>
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[8]">
<image v-show="shouldShowContent(8)" class="bg-image"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/home/footer.png" :lazy-load="true"
mode="aspectFill"></image>
<!-- <image class="qrcode-txt" v-show="shouldShowContent(8)"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/home/qrcode-txt.png" :lazy-load="true"
mode="aspectFill" :show-menu-by-longpress="true"></image> -->
<image class="qrcode-txt" v-show="shouldShowContent(8)" @click="gotoPath('/subPackages/techan/detail?id=32')"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/home/qrcode-btn.png" :lazy-load="true"
mode="widthFix" :show-menu-by-longpress="true"></image>
<!-- <image class="qrcode-txts" v-show="shouldShowContent(8)"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/home/qrcode-txtss.png" :lazy-load="true"
mode="widthFix"></image> -->
</template>
</view>
</swiper-item>
<swiper-item>
<template v-if="loadedPages[9]">
<image v-show="shouldShowContent(9)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/footers.png" :lazy-load="true" mode="aspectFill"></image>
<image v-show="shouldShowContent(9)" 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>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[10]">
<messageBoard class="message-board" />
</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 /> -->
<messagePop />
<!-- <BackgroundMusic /> -->
<MusicControl />
</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,
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
},
{
text: '购物车',
targetIndex: 100
3 months ago
}
],
chapterPaths: {
4: '/taozi/chapter1/chapter1',
5: '/taozi/chapter2/chapter2',
6: '/taozi/chapter3/chapter3',
7: '/taozi/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) {
if(idx == 100) {
// 去购物车
this.gotoPath('/subPackages/user/gwc')
return;
}
3 months ago
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;
}
},
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: #fff;
}
.loadedPages-three-content {
display: flex;
align-items: center;
flex-direction: column;
justify-content: space-between;
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: 100%;
height: 100%;
}
.arrow-content {
width: 100%;
position: absolute;
bottom: 5%;
left: 50%;
transform: translate(-50%, 0);
display: flex;
align-items: center;
justify-content: center;
}
.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;
}
</style>