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.
 
 
 
 

262 lines
5.1 KiB

<template>
<view>
<!-- 遮罩层 -->
<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>
</view>
</template>
<script>
export default {
name: "SideNav",
props: {
currentIndex: {
type: Number,
default: 0,
},
},
data() {
return {
showMenu: false,
iconRotated: false,
iconBounceBack: false,
menuItems: [
{
text: "序章",
targetIndex: 0,
path: "/pig/home/home",
},
{
text: "第一章猪的起源",
targetIndex: 4,
path: "/pig/chapter1/chapter1",
},
{
text: "第二章驯为良伴",
targetIndex: 5,
path: "/pig/chapter2/chapter2",
},
{
text: "第三章身份之谜",
targetIndex: 6,
path: "/pig/chapter3/chapter3",
},
{
text: "第四章 东方之猪",
targetIndex: 7,
path: "/pig/chapter4/chapter4",
},
{
text: "点击购买",
targetIndex: 8,
path: "/subPackages/techan/detail?id=38",
},
{
text: '购物车',
targetIndex: 10,
path: "/subPackages/user/gwc"
}
],
};
},
methods: {
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(targetIndex) {
const menuItem = this.menuItems.find(
(item) => item.targetIndex === targetIndex
);
if (menuItem) {
// 如果有path属性,进行页面跳转
if (menuItem.path) {
uni.navigateTo({
url:
menuItem.path +
(targetIndex > 0 ? `?targetIndex=${targetIndex}` : ""),
});
} else {
// 否则触发事件让父组件处理
this.$emit("navigate", targetIndex);
}
}
this.closeMenu();
},
isItemActive(item) {
return this.currentIndex === item.targetIndex;
},
},
};
</script>
<style lang="scss" scoped>
.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;
}
</style>