11<script setup>
2- import {navigationData } from ' ./data.js' ;
3- import {ElBacktop , ElAffix , ElScrollbar , ElLink } from ' element-plus'
2+ import { navigationData } from ' ./data.js' ;
3+ import { ElBacktop , ElScrollbar , ElLink , ElInput } from ' element-plus'
44import WebLink from ' ./WebLink.vue'
5+ import { ref , onMounted , onBeforeUnmount , nextTick , computed } from ' vue'
56
67// import {WebLink} from 'vitepress/theme'
78
8- const scrollToAnchor = (anchor ) => {
9- const target = document .querySelector (anchor);
9+ const activeAnchor = ref (' ' )
10+ const searchText = ref (' ' )
11+ const filteredNav = computed (() => {
12+ const q = searchText .value .trim ()
13+ if (! q) return navigationData
14+ return navigationData .filter ((s ) => s .title .includes (q))
15+ })
16+
17+ let headingEls = []
18+
19+ const collectHeadingEls = () => {
20+ headingEls = navigationData
21+ .map ((s ) => document .getElementById (s .title ))
22+ .filter (Boolean )
23+ }
24+
25+ const handleScroll = () => {
26+ const navHeight = document .querySelector (' header' )? .offsetHeight || 0
27+ const fromTop = window .scrollY + navHeight + 12
28+ let current = ' '
29+ for (const s of navigationData) {
30+ const el = document .getElementById (s .title )
31+ if (! el) continue
32+ if (el .offsetTop <= fromTop) {
33+ current = ' #' + s .title
34+ } else {
35+ break
36+ }
37+ }
38+ if (current) activeAnchor .value = current
39+ }
40+
41+ const scrollToAnchor = (id ) => {
42+ const target = document .getElementById (id)
1043 if (target) {
11- const navHeight = document . querySelector ( ' header ' ). offsetHeight ; // 获取导航栏的高度
12- const offset = target .getBoundingClientRect (). top - navHeight; // 计算滚动偏移量
13- window . scrollTo ({top : offset, behavior : ' smooth ' }); // 滚动到目标位置
44+ // 使用 scrollIntoView,使滚动更加稳定;配合内容区的 scroll-margin-top 避免被头部遮挡
45+ target .scrollIntoView ({ behavior : ' smooth ' , block : ' start ' })
46+ activeAnchor . value = ' # ' + id
1447 }
1548}
1649
50+ onMounted (() => {
51+ nextTick (() => {
52+ collectHeadingEls ()
53+ window .addEventListener (' scroll' , handleScroll, { passive: true })
54+ handleScroll ()
55+ })
56+ })
57+
58+ onBeforeUnmount (() => {
59+ window .removeEventListener (' scroll' , handleScroll)
60+ })
61+
1762< / script>
1863
1964< template>
@@ -32,15 +77,25 @@ const scrollToAnchor = (anchor) => {
3277 < / el- backtop>
3378 < div class = " page" >
3479 < div class = " my-nav" >
35- <el-affix :offset =" 5" >
36- <el-scrollbar height =" 100vh" >
37- <el-link type =" primary" v-for =" (sites, index) in navigationData" :key =" index"
38- @click =" scrollToAnchor('#' + sites.title)" >{{ sites.title }}
39- </el-link >
40- <el-link type =" primary" href =" https://spiderbox.cn/" target =" _blank" >资源链接来源于《虫盒》</el-link >
41- <el-link type =" primary" href =" #" >持续更新中</el-link >
42- </el-scrollbar >
43- </el-affix >
80+ < div class = " nav-card" >
81+ < div class = " nav-search" >
82+ < el- input v- model= " searchText" placeholder= " 搜索分类" clearable size= " small" / >
83+ < / div>
84+ < el- scrollbar height= " 100vh" >
85+ < el- link
86+ v- for = " (sites, index) in filteredNav"
87+ : key= " index"
88+ type= " primary"
89+ : underline= " false"
90+ : class = " { 'is-active': activeAnchor === '#' + sites.title }"
91+ : title= " sites.title"
92+ href= " #"
93+ @click .prevent = " scrollToAnchor(sites.title)"
94+ >
95+ {{ sites .title }}
96+ < / el- link>
97+ < / el- scrollbar>
98+ < / div>
4499 < / div>
45100 < div>
46101<!-- < el- link type= " primary" href= " https://www.qg.net/product/proxyip.html?source=star" target= " _blank" > -->
@@ -54,32 +109,80 @@ const scrollToAnchor = (anchor) => {
54109
55110
56111 < WebLink : datalist= " navigationData" >< / WebLink>
112+ < div class = " source-note" >
113+ 资源链接来源于
114+ < a href= " https://spiderbox.cn/" target= " _blank" rel= " noopener noreferrer" > 《虫盒》< / a>
115+ < span class = " note-updating" > 持续更新中< / span>
116+ < / div>
57117 < / div>
58118 < / div>
59119< / template>
60120
61121< style scoped>
62122.my - nav {
63- padding : 0px 5px ;
123+ padding: 8px ;
124+ position: sticky;
125+ top: 8px ;
126+ align- self : flex- start;
127+ z- index: 20 ;
128+ }
129+
130+ .nav - card {
131+ background: var (-- el- bg- color- overlay);
132+ border- radius: 12px ;
133+ box- shadow: var (-- el- box- shadow- light);
134+ padding: 10px ;
135+ border: 1px solid var (-- el- border- color- light);
136+ backdrop- filter: blur (6px );
137+ position: relative;
138+ z- index: 20 ;
139+ box- sizing: border- box;
140+ width: 150px ;
141+ /* 居中内部内容 */
142+ display: flex;
143+ flex- direction: column;
144+ align- items: center;
145+ text- align: center;
64146}
65147
148+ .nav - search { padding: 6px 8px 0 ; }
149+
66150.el - scrollbar {
67151 overflow: visible ! important;
152+ width: 100 % ;
68153}
69154
70155.el - link {
71- margin : 0px 8px ;
72- padding : 2px 5px ;
156+ display: block;
157+ margin: 3px 6px ;
158+ padding: 6px 8px ;
73159 text- decoration: none;
74- transition : all 0.3s ease ;
75- color : black ;
76- border : 1px rgb (20 , 143 , 243 ) solid ;
160+ transition: all 0 .2s ease;
161+ color: var (-- el- text- color- primary);
162+ background: var (-- el- color- primary- light- 9 );
163+ border- radius: 10px ;
164+ border: none;
165+ text- align: center;
166+ }
167+
168+ .el - link__inner {
169+ display: block;
170+ min- width: 5em ;
171+ white- space: nowrap ! important;
172+ overflow: hidden;
173+ text- overflow: ellipsis;
77174}
78175
79176.el - link: hover {
80- background-color : rgb (20 , 143 , 243 );
81- color : white ;
82- transform : scale (1.05 );
177+ background: var (-- el- color- primary);
178+ color: #fff;
179+ transform: translateX (2px );
180+ }
181+
182+ .el - link .is - active {
183+ background: linear- gradient (90deg , var (-- el- color- primary), var (-- el- color- primary- light- 3 ));
184+ color: #fff;
185+ box- shadow: 0 4px 12px rgba (24 , 144 , 255 , 0.35 );
83186}
84187
85188.el - link .el - icon-- right .el - icon {
@@ -88,5 +191,25 @@ const scrollToAnchor = (anchor) => {
88191
89192.page {
90193 display: flex;
194+ gap: 12px ;
195+ }
196+
197+ .source - note {
198+ background: var (-- el- color- primary- light- 9 );
199+ border- radius: 12px ;
200+ padding: 10px 14px ;
201+ margin: 12px 0 0 ;
202+ color: var (-- el- text- color- primary);
203+ font- weight: 600 ;
204+ }
205+ .source - note a {
206+ color: var (-- el- text- color- primary);
207+ text- decoration: none;
208+ }
209+ .source - note a: hover { text- decoration: underline; }
210+ .source - note .note - updating {
211+ font- weight: 500 ;
212+ color: var (-- el- text- color- secondary);
213+ margin- left: 8px ;
91214}
92215< / style>
0 commit comments