Sidebar.vue
4.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
<template>
<nav
class="max-[768px]:flex-[0] flex-shrink-0 scroll-container w-56 bg-white dark:bg-[#272929] shadow-lg h-[calc(100vh-4rem)] sticky top-16 overflow-y-auto transition-colors duration-300"
>
<div class="md:p-4 p-2">
<h2 class="text-lg font-semibold mb-4 text-gray-700 dark:text-[#c6c9cf]">
工具分类
</h2>
<ul id="menu" class="space-y-1">
<li
:id="`menu-${category.id}`"
v-for="(category, index) in sortList"
:key="index"
class="menu-item"
>
<div
class="w-full flex items-center justify-between p-3 text-[#515c6b] dark:text-[#c6c9cf] hover:text-[#5961f9] dark:hover:text-white rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors cursor-pointer"
>
<a
:href="`#term-${category.id}`"
@click="handleCategoryClick($event, category.id, category)"
class="flex items-center space-x-2 flex-1"
>
<i
class="iconfont text-sm"
:class="[`icon-${category.icon}`]"
></i>
<span class="text-sm">{{ category.label }}</span>
</a>
<button
v-if="category.children && category.children.length > 0"
@click.stop="toggleExpand(index)"
class="p-1 hover:bg-gray-200 dark:hover:bg-gray-600 rounded transition-colors"
:aria-label="activeCategory === index ? '收起分类' : '展开分类'"
>
<el-icon
size="14px"
class="text-[#515c6b] dark:text-[#c6d9df] transition-transform duration-300"
:class="{ 'rotate-90': activeCategory === index }"
>
<ArrowRightBold />
</el-icon>
</button>
</div>
<transition name="slide">
<ul v-show="activeCategory === index" class="ml-4 space-y-0.5">
<li
v-for="(subItem, subIndex) in category.children"
:key="subItem.id"
:id="`menu-${category.id}-${subItem.id}`"
>
<a
:href="`#term-${category.id}-${subItem.id}`"
class="block text-sm py-2 px-3 rounded hover:bg-gray-100 dark:hover:bg-gray-700 text-[#515c6b] dark:text-[#c6c9cf] hover:text-[#5961f9] dark:hover:text-white transition-colors"
@click.stop="
handleSubCategoryClick($event, category.id, subItem.id)
"
>
{{ subItem.label }}
</a>
</li>
</ul>
</transition>
</li>
</ul>
</div>
</nav>
</template>
<script setup lang="ts">
import type { classifyType } from "~/api/types/classify";
import { ArrowRightBold } from "@element-plus/icons-vue";
const sortList = useState<classifyType[]>("sortTree");
const activeCategory = ref<number | null>(0);
const route = useRoute();
const router = useRouter();
const config = useRuntimeConfig();
const { setActiveSubCategory } = useActiveSubCategory();
const toggleExpand = (index: number) => {
if (activeCategory.value === index) {
activeCategory.value = null;
} else {
activeCategory.value = index;
}
};
const scrollToElement = (elementId: string) => {
const element = document.getElementById(elementId);
if (element) {
element.scrollIntoView({
behavior: "smooth",
block: "center",
});
return true;
}
return false;
};
const handleCategoryClick = (
event: Event,
id: number,
SubCategory: classifyType
) => {
event.preventDefault();
if (SubCategory.children && SubCategory.children.length > 0) {
const targetChildId = `term-${id}-${SubCategory.children[0].id}`;
setActiveSubCategory(targetChildId);
} else {
setActiveSubCategory(null);
}
const targetId = `term-${id}`;
if (route.path === "/") {
scrollToElement(targetId);
} else {
router.push(`/#${targetId}`);
}
};
const handleSubCategoryClick = (
event: Event,
parentId: number,
subId: number
) => {
event.preventDefault();
const targetId = `term-${parentId}-${subId}`;
setActiveSubCategory(targetId);
if (route.path === "/") {
scrollToElement(targetId);
} else {
router.push(`/#${targetId}`);
}
};
</script>