快捷菜单
常用功能一站直达
更多功能请点顶栏「快捷菜单」

1帮我写个简单的相册:
2
3图片按时间排序,每张图片下有日期,及文字描述。
4
5这个相册主要记录下一对小情侣之间的美好图片回忆。
6
7请帮我输出具体的代码。我将为您创建一个温馨浪漫的情侣回忆相册网页,按时间排序展示照片,并包含日期和文字描述。这个设计将采用柔和的色调,营造出甜蜜温馨的氛围,同时确保照片展示清晰、交互友好。
::: dtails 具体代码
couple-album.html文件:
1<!DOCTYPE html>
2<html lang="zh-CN">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>我们的回忆 | 爱情相册</title>
7 <!-- 引入Tailwind CSS -->
8 <script src="https://cdn.tailwindcss.com"></script>
9 <!-- 引入Font Awesome -->
10 <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
11
12 <!-- 配置Tailwind自定义颜色和字体 -->
13 <script>
14 tailwind.config = {
15 theme: {
16 extend: {
17 colors: {
18 primary: '#E94560', // 浪漫粉红色
19 secondary: '#1A1A2E', // 深色背景
20 accent: '#FFD700', // 金色点缀
21 light: '#F7F7F9', // 浅色背景
22 },
23 fontFamily: {
24 romantic: ['"Dancing Script"', 'cursive', 'sans-serif'],
25 sans: ['Inter', 'system-ui', 'sans-serif'],
26 },
27 }
28 }
29 }
30 </script>
31
32 <!-- 自定义工具类 -->
33 <style type="text/tailwindcss">
34 @layer utilities {
35 .content-auto {
36 content-visibility: auto;
37 }
38 .photo-card-shadow {
39 box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05), 0 0 0 1px rgba(233, 69, 96, 0.1);
40 }
41 .album-gradient {
42 background: linear-gradient(120deg, #fdfbfb 0%, #f7f4f7 100%);
43 }
44 }
45 </style>
46
47 <!-- 引入Google字体 -->
48 <link href="https://fonts.googleapis.com/css2?family=Dancing+Script:wght@400;700&family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet">
49</head>
50
51<body class="album-gradient min-h-screen">
52 <!-- 顶部导航栏 -->
53 <header class="sticky top-0 z-50 bg-white/80 backdrop-blur-md shadow-sm transition-all duration-300">
54 <div class="container mx-auto px-4 py-4 flex justify-between items-center">
55 <h1 class="text-3xl md:text-4xl font-romantic text-primary">
56 <i class="fa fa-heart mr-2 animate-pulse"></i>我们的故事
57 </h1>
58 <div class="flex items-center space-x-4">
59 <button id="sortButton" class="flex items-center text-secondary hover:text-primary transition-colors">
60 <i class="fa fa-sort mr-1"></i>
61 <span>按时间</span>
62 </button>
63 <button id="addPhotoBtn" class="bg-primary hover:bg-primary/90 text-white px-4 py-2 rounded-full shadow-md hover:shadow-lg transition-all transform hover:-translate-y-0.5">
64 <i class="fa fa-plus mr-1"></i>添加回忆
65 </button>
66 </div>
67 </div>
68 </header>
69
70 <!-- 主内容区 -->
71 <main class="container mx-auto px-4 py-8">
72 <!-- 相册介绍 -->
73 <div class="text-center mb-12 max-w-3xl mx-auto">
74 <h2 class="text-[clamp(1.8rem,4vw,2.5rem)] font-romantic text-secondary mb-4">记录我们的每一个美好瞬间</h2>
75 <p class="text-gray-600 text-lg">时光荏苒,爱意绵长。这里收藏着属于我们的点点滴滴,每一张照片都是一段珍贵的回忆。</p>
76 </div>
77
78 <!-- 照片筛选标签 -->
79 <div class="flex flex-wrap justify-center gap-2 mb-8">
80 <button class="filter-tag active px-4 py-2 rounded-full bg-primary text-white" data-filter="all">全部回忆</button>
81 <button class="filter-tag px-4 py-2 rounded-full bg-white text-gray-700 hover:bg-primary/10 transition-colors" data-filter="date">约会时光</button>
82 <button class="filter-tag px-4 py-2 rounded-full bg-white text-gray-700 hover:bg-primary/10 transition-colors" data-filter="travel">旅行足迹</button>
83 <button class="filter-tag px-4 py-2 rounded-full bg-white text-gray-700 hover:bg-primary/10 transition-colors" data-filter="festival">节日庆典</button>
84 <button class="filter-tag px-4 py-2 rounded-full bg-white text-gray-700 hover:bg-primary/10 transition-colors" data-filter="daily">日常点滴</button>
85 </div>
86
87 <!-- 照片网格 -->
88 <div id="photoGrid" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
89 <!-- 照片将通过JavaScript动态加载 -->
90 </div>
91
92 <!-- 加载更多按钮 -->
93 <div class="text-center mt-12">
94 <button id="loadMoreBtn" class="px-6 py-3 bg-white text-primary border border-primary rounded-full hover:bg-primary hover:text-white transition-all duration-300 shadow-sm hover:shadow">
95 加载更多回忆 <i class="fa fa-angle-down ml-1"></i>
96 </button>
97 </div>
98 </main>
99
100 <!-- 照片查看模态框 -->
101 <div id="photoModal" class="fixed inset-0 bg-black/80 z-50 hidden flex items-center justify-center p-4">
102 <div class="relative max-w-4xl w-full max-h-[90vh]">
103 <button id="closeModal" class="absolute -top-12 right-0 text-white text-2xl hover:text-primary transition-colors">
104 <i class="fa fa-times"></i>
105 </button>
106 <img id="modalImage" src="" alt="照片大图" class="max-w-full max-h-[80vh] object-contain mx-auto">
107 <div class="bg-white/90 backdrop-blur-sm p-4 mt-4 rounded-lg">
108 <h3 id="modalDate" class="text-primary font-semibold text-lg mb-2"></h3>
109 <p id="modalDescription" class="text-gray-700"></p>
110 </div>
111 </div>
112 </div>
113
114 <!-- 添加照片模态框 -->
115 <div id="addPhotoModal" class="fixed inset-0 bg-black/60 z-50 hidden items-center justify-center p-4">
116 <div class="bg-white rounded-xl p-6 max-w-md w-full">
117 <div class="flex justify-between items-center mb-4">
118 <h3 class="text-xl font-romantic text-primary">添加新回忆</h3>
119 <button id="closeAddModal" class="text-gray-500 hover:text-primary">
120 <i class="fa fa-times"></i>
121 </button>
122 </div>
123 <form id="addPhotoForm" class="space-y-4">
124 <div>
125 <label class="block text-gray-700 mb-1" for="photoDate">日期</label>
126 <input type="date" id="photoDate" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary/50">
127 </div>
128 <div>
129 <label class="block text-gray-700 mb-1" for="photoDescription">描述这段回忆</label>
130 <textarea id="photoDescription" rows="3" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary/50" placeholder="记录下当时的心情和故事..."></textarea>
131 </div>
132 <div>
133 <label class="block text-gray-700 mb-1" for="photoCategory">分类</label>
134 <select id="photoCategory" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary/50">
135 <option value="date">约会时光</option>
136 <option value="travel">旅行足迹</option>
137 <option value="festival">节日庆典</option>
138 <option value="daily">日常点滴</option>
139 </select>
140 </div>
141 <div>
142 <label class="block text-gray-700 mb-1" for="photoUrl">照片地址</label>
143 <input type="text" id="photoUrl" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary/50" placeholder="输入照片的URL地址">
144 </div>
145 <button type="submit" class="w-full bg-primary hover:bg-primary/90 text-white py-3 rounded-lg transition-colors">
146 保存回忆
147 </button>
148 </form>
149 </div>
150 </div>
151
152 <!-- 页脚 -->
153 <footer class="bg-secondary text-white py-8 mt-16">
154 <div class="container mx-auto px-4 text-center">
155 <p class="font-romantic text-2xl mb-2">我们的故事,未完待续...</p>
156 <p class="text-gray-300 text-sm">© <span id="currentYear"></span> 爱与回忆 | 永远在一起</p>
157 </div>
158 </footer>
159
160 <script>
161 // 照片数据 - 按时间倒序排列(最新的在前)
162 const photos = [
163 {
164 id: 1,
165 date: '2023-10-15',
166 description: '第一次一起看海,海风很轻,你的笑容很甜。我们在沙滩上写下彼此的名字,约定要一起看遍世界的每一片海。',
167 url: 'https://picsum.photos/id/1039/800/600',
168 category: 'date'
169 },
170 {
171 id: 2,
172 date: '2023-09-21',
173 description: '中秋节一起做月饼,虽然形状不太完美,但这是我们一起完成的第一个节日美食。月光下的你,比月亮还要温柔。',
174 url: 'https://picsum.photos/id/292/800/600',
175 category: 'festival'
176 },
177 {
178 id: 3,
179 date: '2023-08-05',
180 description: '周末一起去郊外露营,晚上躺在帐篷里看星星,你说要把最亮的那颗星星命名为我们的名字。',
181 url: 'https://picsum.photos/id/883/800/600',
182 category: 'travel'
183 },
184 {
185 id: 4,
186 date: '2023-07-10',
187 description: '第一次一起做饭,你负责洗菜我负责炒,虽然有点手忙脚乱,但吃到嘴里的那一刻觉得无比幸福。',
188 url: 'https://picsum.photos/id/431/800/600',
189 category: 'daily'
190 },
191 {
192 id: 5,
193 date: '2023-06-01',
194 description: '儿童节一起去了游乐园,你像个孩子一样拉着我玩遍了所有项目,旋转木马上的笑容是我见过最美的风景。',
195 url: 'https://picsum.photos/id/338/800/600',
196 category: 'date'
197 },
198 {
199 id: 6,
200 date: '2023-05-20',
201 description: '520收到的惊喜,你说每天都要像今天一样爱我。其实有你的每一天,都是情人节。',
202 url: 'https://picsum.photos/id/240/800/600',
203 category: 'festival'
204 }
205 ];
206
207 // 页面加载时显示的照片数量
208 let visibleCount = 6;
209 // 当前排序方式 (desc: 倒序, asc: 正序)
210 let sortOrder = 'desc';
211 // 当前筛选类别
212 let currentFilter = 'all';
213
214 // DOM元素
215 const photoGrid = document.getElementById('photoGrid');
216 const loadMoreBtn = document.getElementById('loadMoreBtn');
217 const sortButton = document.getElementById('sortButton');
218 const photoModal = document.getElementById('photoModal');
219 const modalImage = document.getElementById('modalImage');
220 const modalDate = document.getElementById('modalDate');
221 const modalDescription = document.getElementById('modalDescription');
222 const closeModal = document.getElementById('closeModal');
223 const addPhotoBtn = document.getElementById('addPhotoBtn');
224 const addPhotoModal = document.getElementById('addPhotoModal');
225 const closeAddModal = document.getElementById('closeAddModal');
226 const addPhotoForm = document.getElementById('addPhotoForm');
227 const filterTags = document.querySelectorAll('.filter-tag');
228 const currentYearEl = document.getElementById('currentYear');
229
230 // 设置当前年份
231 currentYearEl.textContent = new Date().getFullYear();
232
233 // 初始化相册
234 function initAlbum() {
235 renderPhotos();
236 setupEventListeners();
237 }
238
239 // 渲染照片
240 function renderPhotos() {
241 // 清空网格
242 photoGrid.innerHTML = '';
243
244 // 筛选和排序照片
245 let filteredPhotos = [...photos];
246
247 // 应用筛选
248 if (currentFilter !== 'all') {
249 filteredPhotos = filteredPhotos.filter(photo => photo.category === currentFilter);
250 }
251
252 // 应用排序
253 filteredPhotos.sort((a, b) => {
254 const dateA = new Date(a.date);
255 const dateB = new Date(b.date);
256 return sortOrder === 'desc' ? dateB - dateA : dateA - dateB;
257 });
258
259 // 限制显示数量
260 const photosToShow = filteredPhotos.slice(0, visibleCount);
261
262 // 没有照片时显示提示
263 if (photosToShow.length === 0) {
264 photoGrid.innerHTML = `
265 <div class="col-span-full text-center py-12">
266 <i class="fa fa-image text-gray-300 text-5xl mb-4"></i>
267 <p class="text-gray-500">没有找到符合条件的回忆</p>
268 </div>
269 `;
270 return;
271 }
272
273 // 创建照片卡片
274 photosToShow.forEach(photo => {
275 const formattedDate = formatDate(photo.date);
276
277 const photoCard = document.createElement('div');
278 photoCard.className = 'photo-card bg-white rounded-xl overflow-hidden photo-card-shadow transform transition-all duration-300 hover:-translate-y-2 hover:shadow-xl';
279 photoCard.dataset.category = photo.category;
280
281 photoCard.innerHTML = `
282 <div class="relative overflow-hidden group">
283 <img src="${photo.url}" alt="回忆照片" class="w-full h-64 object-cover transition-transform duration-500 group-hover:scale-110">
284 <div class="absolute inset-0 bg-primary/20 opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex items-center justify-center">
285 <button class="view-photo-btn bg-white text-primary p-3 rounded-full transform translate-y-4 group-hover:translate-y-0 transition-transform duration-300">
286 <i class="fa fa-search-plus"></i>
287 </button>
288 </div>
289 </div>
290 <div class="p-5">
291 <div class="flex justify-between items-center mb-2">
292 <span class="text-primary font-semibold">${formattedDate}</span>
293 <span class="text-xs px-2 py-1 rounded-full bg-primary/10 text-primary">
294 ${getCategoryName(photo.category)}
295 </span>
296 </div>
297 <p class="text-gray-600 line-clamp-3">${photo.description}</p>
298 </div>
299 `;
300
301 photoGrid.appendChild(photoCard);
302
303 // 添加查看照片事件
304 const viewBtn = photoCard.querySelector('.view-photo-btn');
305 viewBtn.addEventListener('click', () => openPhotoModal(photo));
306
307 // 点击照片也可以查看大图
308 const img = photoCard.querySelector('img');
309 img.addEventListener('click', () => openPhotoModal(photo));
310 });
311
312 // 控制"加载更多"按钮显示
313 if (visibleCount >= filteredPhotos.length) {
314 loadMoreBtn.classList.add('hidden');
315 } else {
316 loadMoreBtn.classList.remove('hidden');
317 }
318 }
319
320 // 格式化日期
321 function formatDate(dateString) {
322 const date = new Date(dateString);
323 return date.toLocaleDateString('zh-CN', {
324 year: 'numeric',
325 month: 'long',
326 day: 'numeric'
327 });
328 }
329
330 // 获取分类名称
331 function getCategoryName(category) {
332 const categories = {
333 'date': '约会时光',
334 'travel': '旅行足迹',
335 'festival': '节日庆典',
336 'daily': '日常点滴'
337 };
338 return categories[category] || category;
339 }
340
341 // 打开照片模态框
342 function openPhotoModal(photo) {
343 modalImage.src = photo.url;
344 modalImage.alt = photo.description;
345 modalDate.textContent = formatDate(photo.date);
346 modalDescription.textContent = photo.description;
347 photoModal.classList.remove('hidden');
348 document.body.style.overflow = 'hidden'; // 防止背景滚动
349 }
350
351 // 关闭照片模态框
352 function closePhotoModal() {
353 photoModal.classList.add('hidden');
354 document.body.style.overflow = ''; // 恢复滚动
355 }
356
357 // 切换排序方式
358 function toggleSortOrder() {
359 sortOrder = sortOrder === 'desc' ? 'asc' : 'desc';
360 renderPhotos();
361
362 // 更新排序按钮文本
363 const sortText = sortButton.querySelector('span');
364 sortText.textContent = sortOrder === 'desc' ? '按时间(最新在前)' : '按时间(最早在前)';
365 }
366
367 // 加载更多照片
368 function loadMorePhotos() {
369 visibleCount += 3;
370 renderPhotos();
371 }
372
373 // 切换筛选类别
374 function setFilter(category) {
375 currentFilter = category;
376 visibleCount = 6; // 重置显示数量
377
378 // 更新筛选标签样式
379 filterTags.forEach(tag => {
380 if (tag.dataset.filter === category) {
381 tag.classList.add('bg-primary', 'text-white');
382 tag.classList.remove('bg-white', 'text-gray-700', 'hover:bg-primary/10');
383 } else {
384 tag.classList.remove('bg-primary', 'text-white');
385 tag.classList.add('bg-white', 'text-gray-700', 'hover:bg-primary/10');
386 }
387 });
388
389 renderPhotos();
390 }
391
392 // 打开添加照片模态框
393 function openAddPhotoModal() {
394 addPhotoModal.classList.remove('hidden');
395 addPhotoModal.classList.add('flex');
396 document.body.style.overflow = 'hidden';
397 }
398
399 // 关闭添加照片模态框
400 function closeAddPhotoModalFunc() {
401 addPhotoModal.classList.add('hidden');
402 addPhotoModal.classList.remove('flex');
403 document.body.style.overflow = '';
404 addPhotoForm.reset();
405 }
406
407 // 添加新照片
408 function addNewPhoto(e) {
409 e.preventDefault();
410
411 const date = document.getElementById('photoDate').value;
412 const description = document.getElementById('photoDescription').value;
413 const category = document.getElementById('photoCategory').value;
414 const url = document.getElementById('photoUrl').value;
415
416 // 简单验证
417 if (!date || !description || !url) {
418 alert('请填写所有必填字段');
419 return;
420 }
421
422 // 创建新照片对象
423 const newPhoto = {
424 id: photos.length + 1,
425 date,
426 description,
427 url,
428 category
429 };
430
431 // 添加到照片数组
432 photos.unshift(newPhoto);
433
434 // 重新渲染
435 renderPhotos();
436
437 // 关闭模态框
438 closeAddPhotoModalFunc();
439
440 // 显示成功提示
441 alert('回忆添加成功!');
442 }
443
444 // 设置事件监听器
445 function setupEventListeners() {
446 // 排序按钮
447 sortButton.addEventListener('click', toggleSortOrder);
448
449 // 加载更多按钮
450 loadMoreBtn.addEventListener('click', loadMorePhotos);
451
452 // 关闭照片模态框
453 closeModal.addEventListener('click', closePhotoModal);
454
455 // 点击模态框背景关闭
456 photoModal.addEventListener('click', (e) => {
457 if (e.target === photoModal) {
458 closePhotoModal();
459 }
460 });
461
462 // 添加照片按钮
463 addPhotoBtn.addEventListener('click', openAddPhotoModal);
464
465 // 关闭添加照片模态框
466 closeAddModal.addEventListener('click', closeAddPhotoModalFunc);
467
468 // 点击添加照片模态框背景关闭
469 addPhotoModal.addEventListener('click', (e) => {
470 if (e.target === addPhotoModal) {
471 closeAddPhotoModalFunc();
472 }
473 });
474
475 // 提交添加照片表单
476 addPhotoForm.addEventListener('submit', addNewPhoto);
477
478 // 筛选标签
479 filterTags.forEach(tag => {
480 tag.addEventListener('click', () => {
481 setFilter(tag.dataset.filter);
482 });
483 });
484
485 // 滚动时改变导航栏样式
486 window.addEventListener('scroll', () => {
487 const header = document.querySelector('header');
488 if (window.scrollY > 50) {
489 header.classList.add('py-2', 'shadow');
490 header.classList.remove('py-4');
491 } else {
492 header.classList.add('py-4');
493 header.classList.remove('py-2', 'shadow');
494 }
495 });
496 }
497
498 // 页面加载完成后初始化
499 document.addEventListener('DOMContentLoaded', initAlbum);
500 </script>
501</body>
502</html>:::
这个情侣回忆相册具有以下特点:
您可以直接使用这个代码,也可以根据需要修改照片数据、颜色方案或添加更多功能。
还是不错的。
问题1:在豆包里都有这个红心,为啥在我部署好的服务器上,红心消失了。。。

1前面的 那个 情侣相册模块,请帮我生成一个 vue3版本的组件,不要使用Tailwind CSS,样式直接使用普通css写在组件内。我将为您创建一个 Vue3 版本的情侣相册组件,不依赖 Tailwind CSS,使用原生 CSS 编写样式并整合在组件内部,保持原有的浪漫风格和功能特性。
具体代码:
这个 Vue3 版本的情侣相册组件具有以下特点:
CoupleAlbum.vue(主组件)和PhotoCard.vue(照片卡片组件),便于维护和扩展。使用方法:
CoupleAlbum组件并使用CoupleAlbum.vue的photos数组中,您可以根据需要修改或扩展<style>部分即可这个组件保持了原有的浪漫风格,同时使用 Vue3 的特性实现了更好的可维护性和扩展性,方便您集成到自己的项目中。
亲自测试:
(1)创建文件:在docs\.vitepress\theme\components\CoupleAlbum目录下创建如下2个文件
具体信息见上文 豆包输出的代码:
1CoupleAlbum.vue
2PhotoCard.vue
(2)注册
编辑docs\.vitepress\theme\index.ts文件,新加如下几行信息:
1// 导入情侣相册组件
2import CoupleAlbum from './components/CoupleAlbum/CoupleAlbum.vue'
3import PhotoCard from './components/CoupleAlbum/PhotoCard.vue'
4
5
6
7 app.component('CoupleAlbum', CoupleAlbum) // 注册情侣相册组件
8 app.component('PhotoCard', PhotoCard)
(3)使用
创建docs\90.关于\70.情侣相册.md文件:
1---
2title: 情侣相册
3date: 2025-01-04 11:19:48
4permalink: /about/love
5layout: page
6categories:
7 - 更多
8tags:
9 - 关于我
10sidebar: false
11article: false
12comment: false
13articleTopTip: false
14articleBottomTip: false
15copyright: false
16---
17
18<CoupleAlbum />(4)验证
运行后,验证:

结束。
1Port 5173 is in use, trying another one...
2
3 vitepress v1.6.4
4
5 ➜ Local: http://localhost:5174/
6 ➜ Network: use --host to expose
7 ➜ press h to show help
8[vite:css] @import must precede all other statements (besides @charset or empty @layer)
9346|
10347| /* 引入Google字体 */
11348| @import url('https://fonts.googleapis.com/css2?family=Dancing+Script:wght@400;700&family=Inter:wght@300;400;500;600&display=swap');
12 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
13349|
14
15
16最近在处理 前面 那个情侣相册 时 ,发现在运行vitepress项目时弹出了一个告警,该如何解决呢?
这个错误提示是由于 CSS 中 @import 语句的位置不正确导致的。在 CSS 规范中,@import 规则必须放在所有其他 CSS 语句之前(@charset 或空的 @layer 除外)。
要解决这个问题,你需要调整代码中 @import 语句的位置:
@import url('https://fonts.googleapis.com/css2?family=Dancing+Script:wght@400;700&family=Inter:wght@300;400;500;600&display=swap'); 这行代码的 CSS 文件@import 语句移动到该 CSS 文件的最顶部,确保它在所有其他 CSS 规则之前例如,错误的写法可能是这样的:
css
1/* 一些其他样式 */
2body {
3 margin: 0;
4}
5
6/* 引入Google字体 */
7@import url('https://fonts.googleapis.com/css2?family=Dancing+Script:wght@400;700&family=Inter:wght@300;400;500;600&display=swap');正确的写法应该是:
css
1/* 引入Google字体 - 放在最顶部 */
2@import url('https://fonts.googleapis.com/css2?family=Dancing+Script:wght@400;700&family=Inter:wght@300;400;500;600&display=swap');
3
4/* 其他样式放在@import之后 */
5body {
6 margin: 0;
7}调整后,VitePress 在编译 CSS 时就不会再报这个错误了。这是一个 CSS 语法规范要求,确保 @import 语句在样式表的最前面。
(1)按上面所述更新自己文件 docs\.vitepress\theme\components\CoupleAlbum\CoupleAlbum.vue
1<template>
2 <div class="couple-album">
3 <!-- 顶部导航 -->
4 <header class="album-header" :class="{ 'scrolled': isScrolled }">
5 <div class="container">
6 <h1 class="album-title">
7 <i class="fa fa-heart"></i> 我们的故事
8 </h1>
9 <div class="header-actions">
10 <button class="sort-btn" @click="toggleSortOrder">
11 <i class="fa fa-sort"></i>
12 <span>{{ sortText }}</span>
13 </button>
14 <button class="add-btn" @click="openAddModal">
15 <i class="fa fa-plus"></i> 添加回忆
16 </button>
17 </div>
18 </div>
19 </header>
20
21 <!-- 主内容区 -->
22 <main class="album-content">
23 <div class="container">
24 <!-- 相册介绍 -->
25 <div class="album-intro">
26 <h2 class="intro-title">记录我们的每一个美好瞬间</h2>
27 <p class="intro-text">时光荏苒,爱意绵长。这里收藏着属于我们的点点滴滴,每一张照片都是一段珍贵的回忆。</p>
28 </div>
29
30 <!-- 筛选标签 -->
31 <div class="filter-tags">
32 <button
33 class="filter-tag"
34 :class="{ active: currentFilter === 'all' }"
35 @click="setFilter('all')"
36 >
37 全部回忆
38 </button>
39 <button
40 class="filter-tag"
41 :class="{ active: currentFilter === 'date' }"
42 @click="setFilter('date')"
43 >
44 约会时光
45 </button>
46 <button
47 class="filter-tag"
48 :class="{ active: currentFilter === 'travel' }"
49 @click="setFilter('travel')"
50 >
51 旅行足迹
52 </button>
53 <button
54 class="filter-tag"
55 :class="{ active: currentFilter === 'festival' }"
56 @click="setFilter('festival')"
57 >
58 节日庆典
59 </button>
60 <button
61 class="filter-tag"
62 :class="{ active: currentFilter === 'daily' }"
63 @click="setFilter('daily')"
64 >
65 日常点滴
66 </button>
67 </div>
68
69 <!-- 照片网格 -->
70 <div class="photo-grid">
71 <PhotoCard
72 v-for="photo in filteredPhotos"
73 :key="photo.id"
74 :photo="photo"
75 :on-photo-click="openPhotoModal"
76 />
77 </div>
78
79 <!-- 无照片提示 -->
80 <div class="no-photos" v-if="filteredPhotos.length === 0">
81 <i class="fa fa-image"></i>
82 <p>没有找到符合条件的回忆</p>
83 </div>
84 </div>
85 </main>
86
87 <!-- 页脚 -->
88 <footer class="album-footer">
89 <div class="container">
90 <p class="footer-quote">我们的故事,未完待续...</p>
91 <p class="footer-copyright">© {{ currentYear }} 爱与回忆 | 永远在一起</p>
92 </div>
93 </footer>
94
95 <!-- 照片查看模态框 -->
96 <div class="modal-backdrop" v-if="isPhotoModalOpen" @click="closePhotoModal">
97 <div class="modal-content" @click.stop>
98 <button class="modal-close" @click="closePhotoModal">
99 <i class="fa fa-times"></i>
100 </button>
101 <img
102 :src="currentPhoto.url"
103 :alt="currentPhoto.description"
104 class="modal-image"
105 >
106 <div class="modal-info">
107 <h3 class="modal-date">{{ currentPhotoFormattedDate }}</h3>
108 <p class="modal-description">{{ currentPhoto.description }}</p>
109 </div>
110 </div>
111 </div>
112
113 <!-- 添加照片模态框 -->
114 <div class="modal-backdrop" v-if="isAddModalOpen" @click="closeAddModal">
115 <div class="modal-content add-modal-content" @click.stop>
116 <div class="add-modal-header">
117 <h3 class="add-modal-title">添加新回忆</h3>
118 <button class="modal-close" @click="closeAddModal">
119 <i class="fa fa-times"></i>
120 </button>
121 </div>
122 <form class="add-photo-form" @submit.prevent="addNewPhoto">
123 <div class="form-group">
124 <label for="photoDate">日期</label>
125 <input type="date" id="photoDate" v-model="newPhoto.date" required>
126 </div>
127 <div class="form-group">
128 <label for="photoDescription">描述这段回忆</label>
129 <textarea
130 id="photoDescription"
131 rows="3"
132 v-model="newPhoto.description"
133 placeholder="记录下当时的心情和故事..."
134 required
135 ></textarea>
136 </div>
137 <div class="form-group">
138 <label for="photoCategory">分类</label>
139 <select id="photoCategory" v-model="newPhoto.category" required>
140 <option value="date">约会时光</option>
141 <option value="travel">旅行足迹</option>
142 <option value="festival">节日庆典</option>
143 <option value="daily">日常点滴</option>
144 </select>
145 </div>
146 <div class="form-group">
147 <label for="photoUrl">照片地址</label>
148 <input
149 type="text"
150 id="photoUrl"
151 v-model="newPhoto.url"
152 placeholder="输入照片的URL地址"
153 required
154 >
155 </div>
156 <button type="submit" class="submit-btn">保存回忆</button>
157 </form>
158 </div>
159 </div>
160 </div>
161 </template>
162
163 <script setup>
164 import { ref, computed, onMounted, reactive } from 'vue';
165 import PhotoCard from './PhotoCard.vue';
166
167 // 照片数据
168 const photos = ref([
169 {
170 id: 1,
171 date: '2023-10-15',
172 description: '第一次一起看海,海风很轻,你的笑容很甜。我们在沙滩上写下彼此的名字,约定要一起看遍世界的每一片海。',
173 url: 'https://picsum.photos/id/1039/800/600',
174 category: 'date'
175 },
176 {
177 id: 2,
178 date: '2023-09-21',
179 description: '中秋节一起做月饼,虽然形状不太完美,但这是我们一起完成的第一个节日美食。月光下的你,比月亮还要温柔。',
180 url: 'https://picsum.photos/id/292/800/600',
181 category: 'festival'
182 },
183 {
184 id: 3,
185 date: '2023-08-05',
186 description: '周末一起去郊外露营,晚上躺在帐篷里看星星,你说要把最亮的那颗星星命名为我们的名字。',
187 url: 'https://picsum.photos/id/883/800/600',
188 category: 'travel'
189 },
190 {
191 id: 4,
192 date: '2023-07-10',
193 description: '第一次一起做饭,你负责洗菜我负责炒,虽然有点手忙脚乱,但吃到嘴里的那一刻觉得无比幸福。',
194 url: 'https://picsum.photos/id/431/800/600',
195 category: 'daily'
196 },
197 {
198 id: 5,
199 date: '2023-06-01',
200 description: '儿童节一起去了游乐园,你像个孩子一样拉着我玩遍了所有项目,旋转木马上的笑容是我见过最美的风景。',
201 url: 'https://picsum.photos/id/338/800/600',
202 category: 'date'
203 },
204 {
205 id: 6,
206 date: '2023-05-20',
207 description: '520收到的惊喜,你说每天都要像今天一样爱我。其实有你的每一天,都是情人节。',
208 url: 'https://picsum.photos/id/240/800/600',
209 category: 'festival'
210 }
211 ]);
212
213 // 状态管理
214 const sortOrder = ref('desc'); // desc: 倒序, asc: 正序
215 const currentFilter = ref('all');
216 const isScrolled = ref(false);
217 const currentYear = ref(new Date().getFullYear());
218
219 // 模态框状态
220 const isPhotoModalOpen = ref(false);
221 const currentPhoto = ref(null);
222 const isAddModalOpen = ref(false);
223
224 // 新照片数据
225 const newPhoto = reactive({
226 date: '',
227 description: '',
228 category: 'date',
229 url: ''
230 });
231
232 // 处理滚动事件
233 onMounted(() => {
234 const handleScroll = () => {
235 isScrolled.value = window.scrollY > 50;
236 };
237
238 window.addEventListener('scroll', handleScroll);
239 return () => window.removeEventListener('scroll', handleScroll);
240 });
241
242 // 计算属性 - 排序和筛选照片
243 const filteredPhotos = computed(() => {
244 // 复制照片数组以避免修改原始数据
245 let result = [...photos.value];
246
247 // 筛选
248 if (currentFilter.value !== 'all') {
249 result = result.filter(photo => photo.category === currentFilter.value);
250 }
251
252 // 排序
253 result.sort((a, b) => {
254 const dateA = new Date(a.date).getTime();
255 const dateB = new Date(b.date).getTime();
256 return sortOrder.value === 'desc' ? dateB - dateA : dateA - dateB;
257 });
258
259 return result;
260 });
261
262 // 排序文本
263 const sortText = computed(() => {
264 return sortOrder.value === 'desc' ? '按时间(最新在前)' : '按时间(最早在前)';
265 });
266
267 // 格式化当前照片日期
268 const currentPhotoFormattedDate = computed(() => {
269 if (!currentPhoto.value) return '';
270 const date = new Date(currentPhoto.value.date);
271 return date.toLocaleDateString('zh-CN', {
272 year: 'numeric',
273 month: 'long',
274 day: 'numeric'
275 });
276 });
277
278 // 切换排序方式
279 const toggleSortOrder = () => {
280 sortOrder.value = sortOrder.value === 'desc' ? 'asc' : 'desc';
281 };
282
283 // 设置筛选类别
284 const setFilter = (category) => {
285 currentFilter.value = category;
286 };
287
288 // 打开照片模态框
289 const openPhotoModal = (photo) => {
290 currentPhoto.value = photo;
291 isPhotoModalOpen.value = true;
292 document.body.style.overflow = 'hidden';
293 };
294
295 // 关闭照片模态框
296 const closePhotoModal = () => {
297 isPhotoModalOpen.value = false;
298 document.body.style.overflow = '';
299 };
300
301 // 打开添加照片模态框
302 const openAddModal = () => {
303 isAddModalOpen.value = true;
304 document.body.style.overflow = 'hidden';
305 // 设置默认日期为今天
306 newPhoto.date = new Date().toISOString().split('T')[0];
307 };
308
309 // 关闭添加照片模态框
310 const closeAddModal = () => {
311 isAddModalOpen.value = false;
312 document.body.style.overflow = '';
313 // 重置表单
314 Object.keys(newPhoto).forEach(key => {
315 newPhoto[key] = key === 'category' ? 'date' : '';
316 });
317 };
318
319 // 添加新照片
320 const addNewPhoto = () => {
321 const newId = photos.value.length > 0
322 ? Math.max(...photos.value.map(p => p.id)) + 1
323 : 1;
324
325 photos.value.unshift({
326 id: newId,
327 ...{...newPhoto}
328 });
329
330 closeAddModal();
331 // 可以添加提示信息
332 alert('回忆添加成功!');
333 };
334 </script>
335
336 <style scoped>
337 /* 引入Google字体 */
338 @import url('https://fonts.googleapis.com/css2?family=Dancing+Script:wght@400;700&family=Inter:wght@300;400;500;600&display=swap');
339
340 /* 基础样式 */
341 .couple-album {
342 font-family: 'Inter', system-ui, sans-serif;
343 background: linear-gradient(120deg, #fdfbfb 0%, #f7f4f7 100%);
344 min-height: 100vh;
345 color: #333;
346 }
347
348 .container {
349 width: 100%;
350 max-width: 1200px;
351 margin: 0 auto;
352 padding: 0 20px;
353 }
354
355 /* 头部样式 */
356 .album-header {
357 background: rgba(255, 255, 255, 0.8);
358 backdrop-filter: blur(4px);
359 padding: 16px 0;
360 position: sticky;
361 top: 0;
362 z-index: 100;
363 box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
364 transition: all 0.3s ease;
365 }
366
367 .album-header.scrolled {
368 padding: 8px 0;
369 box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
370 }
371
372 .album-header .container {
373 display: flex;
374 justify-content: space-between;
375 align-items: center;
376 }
377
378 .album-title {
379 margin: 0;
380 font-size: 24px;
381 font-family: 'Dancing Script', cursive;
382 color: #E94560;
383 display: flex;
384 align-items: center;
385 }
386
387 .album-title i {
388 margin-right: 8px;
389 animation: pulse 2s infinite;
390 }
391
392 @keyframes pulse {
393 0% { opacity: 1; }
394 50% { opacity: 0.6; }
395 100% { opacity: 1; }
396 }
397
398 .header-actions {
399 display: flex;
400 align-items: center;
401 gap: 15px;
402 }
403
404 .sort-btn {
405 background: none;
406 border: none;
407 color: #1A1A2E;
408 cursor: pointer;
409 display: flex;
410 align-items: center;
411 gap: 5px;
412 padding: 5px 10px;
413 border-radius: 4px;
414 transition: color 0.2s ease;
415 }
416
417 .sort-btn:hover {
418 color: #E94560;
419 }
420
421 .add-btn {
422 background: #E94560;
423 color: white;
424 border: none;
425 border-radius: 20px;
426 padding: 8px 16px;
427 display: flex;
428 align-items: center;
429 gap: 5px;
430 cursor: pointer;
431 box-shadow: 0 2px 5px rgba(233, 69, 96, 0.3);
432 transition: all 0.2s ease;
433 }
434
435 .add-btn:hover {
436 background: #d13b54;
437 box-shadow: 0 4px 8px rgba(233, 69, 96, 0.4);
438 transform: translateY(-1px);
439 }
440
441 /* 内容区样式 */
442 .album-content {
443 padding: 40px 0;
444 }
445
446 .album-intro {
447 text-align: center;
448 max-width: 600px;
449 margin: 0 auto 40px;
450 }
451
452 .intro-title {
453 font-family: 'Dancing Script', cursive;
454 font-size: 32px;
455 color: #1A1A2E;
456 margin: 0 0 15px;
457 }
458
459 .intro-text {
460 color: #666;
461 font-size: 16px;
462 margin: 0;
463 }
464
465 /* 筛选标签 */
466 .filter-tags {
467 display: flex;
468 flex-wrap: wrap;
469 justify-content: center;
470 gap: 10px;
471 margin-bottom: 30px;
472 }
473
474 .filter-tag {
475 background: white;
476 border: none;
477 color: #666;
478 padding: 8px 16px;
479 border-radius: 20px;
480 cursor: pointer;
481 transition: all 0.2s ease;
482 }
483
484 .filter-tag.active {
485 background: #E94560;
486 color: white;
487 }
488
489 .filter-tag:not(.active):hover {
490 background: rgba(233, 69, 96, 0.1);
491 }
492
493 /* 照片网格 */
494 .photo-grid {
495 display: grid;
496 grid-template-columns: 1fr;
497 gap: 25px;
498 }
499
500 @media (min-width: 768px) {
501 .photo-grid {
502 grid-template-columns: repeat(2, 1fr);
503 }
504 }
505
506 @media (min-width: 1024px) {
507 .photo-grid {
508 grid-template-columns: repeat(3, 1fr);
509 }
510 }
511
512 /* 无照片提示 */
513 .no-photos {
514 text-align: center;
515 padding: 50px 0;
516 color: #aaa;
517 }
518
519 .no-photos i {
520 font-size: 60px;
521 margin-bottom: 15px;
522 display: block;
523 }
524
525 .no-photos p {
526 margin: 0;
527 font-size: 16px;
528 }
529
530 /* 页脚样式 */
531 .album-footer {
532 background: #1A1A2E;
533 color: white;
534 padding: 30px 0;
535 margin-top: 50px;
536 }
537
538 .footer-quote {
539 font-family: 'Dancing Script', cursive;
540 font-size: 24px;
541 text-align: center;
542 margin: 0 0 10px;
543 }
544
545 .footer-copyright {
546 text-align: center;
547 color: #aaa;
548 font-size: 14px;
549 margin: 0;
550 }
551
552 /* 模态框样式 */
553 .modal-backdrop {
554 position: fixed;
555 top: 0;
556 left: 0;
557 right: 0;
558 bottom: 0;
559 background: rgba(0, 0, 0, 0.8);
560 display: flex;
561 align-items: center;
562 justify-content: center;
563 z-index: 1000;
564 padding: 20px;
565 }
566
567 .modal-content {
568 background: white;
569 border-radius: 8px;
570 max-width: 900px;
571 width: 100%;
572 position: relative;
573 }
574
575 .modal-close {
576 position: absolute;
577 top: -30px;
578 right: 0;
579 background: none;
580 border: none;
581 color: white;
582 font-size: 24px;
583 cursor: pointer;
584 transition: color 0.2s ease;
585 }
586
587 .modal-close:hover {
588 color: #E94560;
589 }
590
591 .modal-image {
592 width: 100%;
593 max-height: 70vh;
594 object-fit: contain;
595 }
596
597 .modal-info {
598 padding: 20px;
599 }
600
601 .modal-date {
602 color: #E94560;
603 font-weight: 600;
604 margin: 0 0 10px;
605 }
606
607 .modal-description {
608 color: #666;
609 margin: 0;
610 line-height: 1.6;
611 }
612
613 /* 添加照片模态框 */
614 .add-modal-content {
615 max-width: 500px;
616 width: 100%;
617 }
618
619 .add-modal-header {
620 display: flex;
621 justify-content: space-between;
622 align-items: center;
623 margin-bottom: 20px;
624 padding-bottom: 10px;
625 border-bottom: 1px solid #eee;
626 }
627
628 .add-modal-title {
629 margin: 0;
630 font-family: 'Dancing Script', cursive;
631 color: #E94560;
632 font-size: 22px;
633 }
634
635 .add-photo-form {
636 display: flex;
637 flex-direction: column;
638 gap: 15px;
639 }
640
641 .form-group {
642 display: flex;
643 flex-direction: column;
644 gap: 5px;
645 }
646
647 .form-group label {
648 font-size: 14px;
649 color: #555;
650 }
651
652 .form-group input,
653 .form-group textarea,
654 .form-group select {
655 padding: 10px;
656 border: 1px solid #ddd;
657 border-radius: 4px;
658 font-family: inherit;
659 font-size: 14px;
660 }
661
662 .form-group input:focus,
663 .form-group textarea:focus,
664 .form-group select:focus {
665 outline: none;
666 border-color: #E94560;
667 box-shadow: 0 0 0 2px rgba(233, 69, 96, 0.2);
668 }
669
670 .submit-btn {
671 background: #E94560;
672 color: white;
673 border: none;
674 border-radius: 4px;
675 padding: 12px;
676 font-size: 16px;
677 cursor: pointer;
678 transition: background 0.2s ease;
679 }
680
681 .submit-btn:hover {
682 background: #d13b54;
683 }
684
685
686 </style>
687 
(2)验证
不会再有报错了:(完美)

结束。
日历 · 精选 · 友链 · 更多
如果内容对你有帮助,欢迎请我喝杯咖啡 ☕



One的公众号
爱折腾博客的小白