11<template >
22 <div class =" home" >
3- <el-container >
4- <el-aside width =" 220px" >
3+ <el-container :class =" ['home-container', { 'is-mobile': isMobile }]" >
4+ <el-aside
5+ v-if =" !isMobile"
6+ width =" 220px"
7+ class =" sidebar"
8+ >
59 <div class =" user-profile" >
610 <el-avatar :size =" 100" :src =" avatarUrl" ></el-avatar >
711 <h3 >{{ signature }}</h3 >
1014 <h4 class =" cat-title" >分类</h4 >
1115 <el-tag
1216 :type =" selectedCategories.length === 0 ? 'success' : 'info'"
13- size =" small" class =" cat-item" effect =" light"
14- @click =" clearCategories" >全部</el-tag >
17+ size =" small"
18+ class =" cat-item"
19+ effect =" light"
20+ @click =" clearCategories"
21+ >全部</el-tag >
1522 <el-tag
16- v-for =" c in categories" :key =" c"
23+ v-for =" c in categories"
24+ :key =" c"
1725 :type =" isActive(c) ? 'success' : 'info'"
18- size =" small" class =" cat-item" @click =" toggleCategory(c)"
19- effect =" light" >
26+ size =" small"
27+ class =" cat-item"
28+ effect =" light"
29+ @click =" toggleCategory(c)"
30+ >
2031 {{ c || '未分类' }}
2132 </el-tag >
2233 </div >
2334 </el-aside >
24- <el-main >
35+ <el-main :class = " { 'mobile-main': isMobile } " >
2536 <div class =" toolbar" >
37+ <el-button
38+ v-if =" isMobile"
39+ class =" sidebar-toggle"
40+ type =" primary"
41+ text
42+ @click =" drawerVisible = true"
43+ >
44+ <el-icon ><Menu /></el-icon >
45+ </el-button >
2646 <el-input
2747 v-model =" keyword"
2848 placeholder =" 搜索标题或摘要..."
7494 </el-pagination >
7595 </el-main >
7696 </el-container >
97+ <el-drawer
98+ v-if =" isMobile"
99+ v-model =" drawerVisible"
100+ :with-header =" false"
101+ direction =" ltr"
102+ size =" 260px"
103+ class =" sidebar-drawer"
104+ >
105+ <div class =" sidebar" >
106+ <div class =" user-profile" >
107+ <el-avatar :size =" 100" :src =" avatarUrl" ></el-avatar >
108+ <h3 >{{ signature }}</h3 >
109+ </div >
110+ <div class =" category-panel" >
111+ <h4 class =" cat-title" >分类</h4 >
112+ <el-tag
113+ :type =" selectedCategories.length === 0 ? 'success' : 'info'"
114+ size =" small"
115+ class =" cat-item"
116+ effect =" light"
117+ @click =" clearCategories"
118+ >全部</el-tag >
119+ <el-tag
120+ v-for =" c in categories"
121+ :key =" c"
122+ :type =" isActive(c) ? 'success' : 'info'"
123+ size =" small"
124+ class =" cat-item"
125+ effect =" light"
126+ @click =" toggleCategory(c)"
127+ >
128+ {{ c || '未分类' }}
129+ </el-tag >
130+ </div >
131+ </div >
132+ </el-drawer >
77133 </div >
78134</template >
79135
80136<script >
81- import { ref , onMounted } from ' vue' ;
137+ import { ref , onMounted , onUnmounted } from ' vue' ;
82138import { useRouter } from ' vue-router' ;
83139import api from ' @/api' ;
84140import { loadConfig } from ' @/config' ;
141+ import { Menu } from ' @element-plus/icons-vue' ;
85142
86143export default {
87144 name: ' Home' ,
88145 setup () {
89- const getAvatarUrl = () => {
90- try {
91- return new URL (` ../assets/${ config .avatarPath } ` , import .meta.url).href;
92- } catch (e) {
93- console .error (e);
94- return ' https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png' ;
95- }
96- };
97-
98- const avatarUrl = ref (' ' );
99- const signature = ref (' ' );
100- const articles = ref ([]);
101- const keyword = ref (' ' );
102- const categories = ref ([]);
103- const selectedCategories = ref ([]);
146+ const avatarUrl = ref (' ' );
147+ const signature = ref (' ' );
148+ const articles = ref ([]);
149+ const keyword = ref (' ' );
150+ const categories = ref ([]);
151+ const selectedCategories = ref ([]);
104152 const currentPage = ref (1 );
105153 const pageSize = ref (5 );
106154 const total = ref (0 );
107- const aboutContent = ref (' ' );
155+ const isMobile = ref (false );
156+ const drawerVisible = ref (false );
157+
158+ const updateIsMobile = () => {
159+ isMobile .value = window .innerWidth <= 768 ;
160+ if (! isMobile .value ) {
161+ drawerVisible .value = false ;
162+ }
163+ };
108164
109- const fetchArticles = async (page ) => {
165+ const fetchArticles = async (page ) => {
110166 try {
111- const kw = keyword .value .trim ();
112- let response;
113- if (kw) {
114- // 全文搜索接口不支持分类过滤,清空分类以避免误导
115- response = await api .searchArticles (kw, page, pageSize .value );
116- } else {
117- response = await api .getArticles (page, pageSize .value , selectedCategories .value );
118- }
167+ const kw = keyword .value .trim ();
168+ let response;
169+ if (kw) {
170+ // 全文搜索接口不支持分类过滤,清空分类以避免误导
171+ response = await api .searchArticles (kw, page, pageSize .value );
172+ } else {
173+ response = await api .getArticles (page, pageSize .value , selectedCategories .value );
174+ }
119175 articles .value = response .data .articles ;
120176 total .value = response .data .total ;
121177 } catch (error) {
@@ -143,11 +199,17 @@ export default {
143199 }
144200 currentPage .value = 1 ;
145201 fetchArticles (currentPage .value );
202+ if (isMobile .value ) {
203+ drawerVisible .value = false ;
204+ }
146205 };
147- const clearCategories = () => {
206+ const clearCategories = () => {
148207 if (keyword .value .trim ()) keyword .value = ' ' ;
149- selectedCategories .value = [];
150- fetchArticles (1 );
208+ selectedCategories .value = [];
209+ fetchArticles (1 );
210+ if (isMobile .value ) {
211+ drawerVisible .value = false ;
212+ }
151213 };
152214 const isActive = (c ) => selectedCategories .value .includes (c);
153215
@@ -187,10 +249,11 @@ export default {
187249 };
188250
189251 onMounted (async () => {
252+ updateIsMobile ();
253+ window .addEventListener (' resize' , updateIsMobile);
190254 try {
191255 const conf = await loadConfig ();
192256 signature .value = conf .signature || ' 鼠鼠很懒,什么都没有留下' ;
193- aboutContent .value = conf .about || ' 鼠鼠很懒,什么都没有留下' ;
194257 try {
195258 avatarUrl .value = new URL (` ../assets/${ conf .avatarPath } ` , import .meta.url).href;
196259 } catch { avatarUrl .value = ' ' ; }
@@ -199,6 +262,10 @@ export default {
199262 fetchArticles (currentPage .value );
200263 });
201264
265+ onUnmounted (() => {
266+ window .removeEventListener (' resize' , updateIsMobile);
267+ });
268+
202269 return {
203270 avatarUrl,
204271 signature,
@@ -207,18 +274,20 @@ export default {
207274 currentPage,
208275 pageSize,
209276 total,
210- handlePageChange,
211- categories,
212- selectedCategories,
213- toggleCategory,
214- clearCategories,
215- isActive,
216- goDetail,
217- splitTags,
218- formatDate,
219- doSearch,
220- clearSearch,
221- aboutContent,
277+ handlePageChange,
278+ categories,
279+ selectedCategories,
280+ toggleCategory,
281+ clearCategories,
282+ isActive,
283+ goDetail,
284+ splitTags,
285+ formatDate,
286+ doSearch,
287+ clearSearch,
288+ isMobile,
289+ drawerVisible,
290+ Menu,
222291 };
223292 },
224293};
@@ -228,14 +297,52 @@ export default {
228297.home {
229298 padding: 20px ;
230299}
300+ .home - container {
301+ min- height: calc (100vh - 80px );
302+ }
303+ .home - container .is - mobile {
304+ flex- direction: column;
305+ }
306+ .sidebar {
307+ display: flex;
308+ flex- direction: column;
309+ gap: 20px ;
310+ }
231311.user - profile {
232312 text- align: center;
233313 background- color: rgba (255 , 255 , 255 , 0.7 );
234314 padding: 20px ;
235315 border- radius: 10px ;
236316}
237- .toolbar { display: flex; justify- content: flex- end; margin- bottom: 12px ; }
238- .search - input { max- width: 360px ; }
317+ .toolbar {
318+ display: flex;
319+ align- items: center;
320+ gap: 12px ;
321+ justify- content: flex- end;
322+ margin- bottom: 12px ;
323+ }
324+ .sidebar - toggle {
325+ display: inline- flex;
326+ align- items: center;
327+ justify- content: center;
328+ padding: 4px 6px ;
329+ border- radius: 6px ;
330+ }
331+ .sidebar - toggle .el - icon {
332+ font- size: 20px ;
333+ }
334+ .search - input {
335+ max- width: 360px ;
336+ }
337+ .mobile - main {
338+ width: 100 % ;
339+ }
340+ .sidebar - drawer {
341+ padding: 0 12px 24px ;
342+ }
343+ .sidebar - drawer .sidebar {
344+ gap: 16px ;
345+ }
239346.category - panel { margin- top: 20px ; background: rgba (255 ,255 ,255 ,.7 ); padding: 12px 14px ; border- radius: 10px ; }
240347.cat - title { margin: 0 0 8px ; font- size: 14px ; color: #333 ; }
241348.cat - item { margin: 4px 6px 4px 0 ; cursor: pointer; user- select: none; }
@@ -280,4 +387,26 @@ export default {
280387 color: #555 ;
281388 line- height: 1.6 ;
282389}
390+
391+ @media (max - width : 768px ) {
392+ .home {
393+ padding: 12px ;
394+ }
395+ .toolbar {
396+ justify- content: space- between;
397+ }
398+ .search - input {
399+ max- width: none;
400+ flex: 1 ;
401+ }
402+ .blog - card {
403+ margin- bottom: 16px ;
404+ }
405+ .user - profile {
406+ padding: 16px ;
407+ }
408+ .category - panel {
409+ margin- top: 12px ;
410+ }
411+ }
283412< / style>
0 commit comments