详细介绍如何在VitePress中开发一个高性能的瀑布流相册组件PhotoGallery，支持MD文件配置、分类切换、图片点击放大、砌墙式布局、暗色模式辉光、省流加载等特性。瀑布流相册组件开发组件需求为了在网站中展示相册，我们需要开发一个瀑布流相册组件，满足以下需求：支持在MD文件中直接配置分类和图片多个分类时支持标签切换砌墙式瀑布流布局（固定卡片宽度，随机高度）图片越后面添加的越显示在前面圆角矩形卡片，无框线鼠标悬浮放大效果暗色模式下有辉光效果点击图片可放大查看（Lightbox）响应式布局页面顶部显示大标题和副标题省流加载机制（每次加载30张，滚动到底部加载更多）组件实现创建文件 docs/.vitepress/theme/components/PhotoGallery.vue： 用图片记录生活 每一张图片都是一个故事，一段回忆，一种情感的表达。 1" class="category-tabs"> {{ category.name }} 往下划动加载更多... 已经到底啦~ <Teleport to="body"> × </Teleport> 组件注册在 docs/.vitepress/theme/index.ts 中注册组件：import PhotoGallery from "./components/PhotoGallery.vue"; export default { enhanceApp({ app }) { app.component('PhotoGallery', PhotoGallery); }, }页面使用在MD文件中使用组件，通过 :categories 属性配置分类和图片：--- title: Mcoo Servers 相册 permalink: /photo layout: page article: false sidebar: false --- <PhotoGallery :categories="[ { name: '新年', photos: [ { src: 'https://example.com/1.jpg', alt: '新年1' }, { src: 'https://example.com/2.jpg', alt: '新年2' }, { src: 'https://example.com/3.jpg', alt: '新年3' }, ] }, { name: '风景', photos: [ { src: 'https://example.com/4.jpg', alt: '风景1' }, { src: 'https://example.com/5.jpg', alt: '风景2' }, ] } ]" />关键实现点1. Props接收MD配置使用 withDefaults 和 defineProps 接收MD文件传入的分类数据：interface Props { categories?: Category[] } const props = withDefaults(defineProps<Props>(), { categories: () => [ { name: '默认', photos: [ { src: '默认图片链接', alt: '照片1' }, ] } ] })2. 砌墙式瀑布流（固定宽度+随机高度）使用JavaScript动态计算每张图片的位置，实现真正的错落有致效果：const CARD_WIDTH = 260 const gap = 16 const columns = Math.max(1, Math.floor((containerWidth + gap) / (CARD_WIDTH + gap))) photoItems.value = displayedPhotos.value.map((photo) => { const minHeight = Math.min(...columnHeights) const minColumn = columnHeights.indexOf(minHeight) const photoHeight = getRandomHeight() // 随机高度 const left = minColumn * (CARD_WIDTH + gap) const top = columnHeights[minColumn] columnHeights[minColumn] += photoHeight + gap return { src, alt, height: photoHeight, left, top } })关键点：卡片宽度固定为 260px高度随机生成（180/220/260/300/340px）使用绝对定位 position: absolute动态计算 left 和 top 位置3. 暗色模式辉光效果使用 :global() 选择器为暗色模式添加辉光：:global(.dark) .photo-item:hover { box-shadow: 0 0 25px rgba(64, 158, 255, 0.35); }4. 图片点击放大（Lightbox + Teleport）使用 Teleport 将灯箱渲染到body，解决定位问题：const showLightbox = ref(false) const openLightbox = (src: string) => { currentImage.value = src showLightbox.value = true }<Teleport to="body"> × </Teleport>5. 省流加载（无限滚动）首次加载45张图片，预加载阈值20张，滚动到底部时加载更多：const displayedCount = ref(45) const BATCH_SIZE = 30 const PRELOAD_THRESHOLD = 20 const handleScroll = () => { if (!hasMore.value) return const scrollHeight = document.documentElement.scrollHeight const scrollTop = document.documentElement.scrollTop const clientHeight = document.documentElement.clientHeight const remaining = currentPhotos.value.length - displayedCount.value if (remaining <= PRELOAD_THRESHOLD) { displayedCount.value = Math.min(displayedCount.value + BATCH_SIZE, currentPhotos.value.length) nextTick(() => { distributePhotos() }) } else if (scrollTop + clientHeight >= scrollHeight - 100) { displayedCount.value = Math.min(displayedCount.value + BATCH_SIZE, currentPhotos.value.length) nextTick(() => { distributePhotos() }) } }6. 初始化加载检测首次加载时，容器宽度可能为0（DOM未渲染完成），需要使用 requestAnimationFrame 循环检测：onMounted(() => { const initGallery = () => { if (masonryRef.value && masonryRef.value.offsetWidth > 0) { distributePhotos() } else { requestAnimationFrame(initGallery) } } requestAnimationFrame(initGallery) window.addEventListener('resize', distributePhotos) window.addEventListener('scroll', handleScroll) })Bug修复记录Bug 1: 首次加载显示单列问题：首次进入相册页面时，图片全部排列在左边，变成长长的一列，需要切换分类后再切回来显示。原因：组件首次挂载时，容器宽度为0，导致列数计算错误。修复：使用 requestAnimationFrame 循环检测容器宽度是否有效：const initGallery = () => { if (masonryRef.value && masonryRef.value.offsetWidth > 0) { distributePhotos() } else { requestAnimationFrame(initGallery) } } requestAnimationFrame(initGallery)Bug 2: 图片重叠问题：图片卡片重叠在一起。原因：CSS中卡片宽度未固定，且列数计算有问题。修复：固定卡片宽度为260px使用固定宽度计算列数给容器添加 overflow: hiddenBug 3: 加载提示位置错误问题："往下划动加载更多"出现在页面正中间，下面还有渐变色带。原因：加载提示放在了瀑布流容器外面。修复：将加载提示放在 masonry-wrapper 内部，紧跟在瀑布流图片后面。参数说明参数类型必填说明categoriesCategory[]否分类数组，默认有一个默认分类Category类型：字段类型说明namestring分类名称photosPhotoItem[]该分类下的图片数组PhotoItem类型：字段类型说明srcstring图片链接（必填）altstring图片描述（可选）效果展示砌墙式布局：固定宽度260px，随机高度，实现错落有致的砌墙效果分类切换：多个分类时显示标签，点击切换省流加载：初始加载30张，滚动到底部时加载更多30张悬浮效果：鼠标放上图片有放大效果和阴影暗色模式：暗色模式下悬浮有蓝色辉光效果点击放大：点击图片可查看大图，点击空白处或关闭按钮退出
详细介绍如何开发一个高性能的自助投稿表单组件SubmissionForm，用于在VitePress中收集用户投稿资源。涵盖组件需求分析、Vue3+TypeScript代码实现、组件注册方法、动态Markdown生成、头像自动匹配、图片与下载链接动态增删、表单验证等核心功能的完整开发流程。自助投稿页面开发组件需求为了方便用户自助投稿资源到资源下载页面，我们需要开发一个投稿表单组件，满足以下需求：收集作品信息（作品名、资源类型）支持可选的B站视频嵌入收集作者信息（作者名、游戏ID、个人主页链接）游戏ID自动匹配服务器成员头像轮播图支持动态增删（最多5张）作品介绍支持换行下载链接支持动态增删，每个链接可设置介绍根据链接类型自动识别下载名称许可证选择一键生成并下载MD文件自动生成符合规范的Frontmatter组件实现创建文件 docs/.vitepress/theme/components/SubmissionForm.vue： 作品信息 作品名 * 资源类型 * 红石 建筑 B站视频（可选） 作者信息 作者名 * 游戏ID * 头像预览： 作者个人主页链接 * 许可证 * CC BY-NC-SA 4.0 CC BY-SA 4.0 MIT 轮播图 *（最多5张） 1" @click="removeImage(index)" class="btn-remove" type="button">× <button v-if="images.length < 5" @click="addImage" class="btn-add" type="button">+ 添加图片 作品介绍 * 下载链接 * 1" @click="removeDownload(index)" class="btn-remove" type="button">× + 添加下载链接 📥 下载 MD 文件 请填写所有必填项后才能下载 组件注册在 docs/.vitepress/theme/index.ts 中注册组件：import SubmissionForm from "./components/SubmissionForm.vue"; export default { enhanceApp({ app }) { app.component('SubmissionForm', SubmissionForm); }, }页面使用创建 docs/@pages/自助投稿.md：--- title: 自助投稿 permalink: /submission --- <SubmissionForm />关键实现点1. 动态增删图片和下载链接使用数组和动态添加/删除函数实现：const images = ref<{ src: string; alt: string }[]>([{ src: '', alt: '' }]) const addImage = () => { if (images.value.length < 5) { images.value.push({ src: '', alt: '' }) } } const removeImage = (index: number) => { if (images.value.length > 1) { images.value.splice(index, 1) } }2. 游戏ID自动匹配头像使用 computed 属性根据游戏ID动态计算头像路径：const avatarPath = computed(() => { if (gameId.value) { return `/mcoo/${gameId.value}.png` } return '' }) const showAvatarPreview = computed(() => { return !!gameId.value })注意：这里需要使用 computed 属性来包装条件判断，直接在模板中使用 v-if="gameId" 可能不会正确触发响应式更新。3. 头像加载错误处理当头像文件不存在时隐藏图片：const handleAvatarError = (event: Event) => { const img = event.target as HTMLImageElement img.style.display = 'none' }4. 下载链接自动识别名称根据链接类型自动识别并生成下载名称：const getDownloadName = (url: string) => { if (url.includes('github.com') && !url.includes('gh-proxy')) { return 'Github' } else if (url.includes('gh-proxy')) { return 'Github 加速' } else if (url.includes('pan.baidu.com') || url.includes('baidu.com')) { return '百度网盘' } else if (url.includes('qm.qq.com') || url.includes('qq.com')) { return 'Mcoo 大型咕咕集散中心' } return '下载链接' }5. 生成带换行的Description作品介绍需要支持换行，在生成MD时转换为 标签：const descLines = workDescription.value.split('\n') descLines.forEach(line => { if (line.trim()) { md += ` ${line.trim()} \n` } else { md += ' \n' } })6. Description自动处理将换行符替换为空格，并截取前150字：const cleanDesc = workDescription.value.replace(/\n/g, ' ').replace(/ /g, ' ').trim() const desc = cleanDesc.length > 150 ? cleanDesc.substring(0, 150) + '...' : cleanDesc7. 本地时间生成使用本地时间而非UTC时间：const dateStr = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0') + '-' + String(now.getDate()).padStart(2, '0') + ' ' + String(now.getHours()).padStart(2, '0') + ':' + String(now.getMinutes()).padStart(2, '0') + ':' + String(now.getSeconds()).padStart(2, '0')8. 表单验证使用 computed 属性进行表单验证：const isValid = computed(() => { const hasValidImages = images.value.some(img => img.src.trim()) const hasValidDownloads = downloads.value.some(d => d.url.trim()) return workName.value.trim() && authorName.value.trim() && gameId.value.trim() && authorLink.value.trim() && workDescription.value.trim() && hasValidImages && hasValidDownloads })参数说明字段类型必填说明bvNumberstring否B站视频BV号workNamestring是作品名称resourceTypestring是资源类型（redstone/building）authorNamestring是作者名称gameIdstring是游戏ID，用于匹配头像authorLinkstring是作者个人主页链接workDescriptionstring是作品介绍licensestring是许可证类型imagesarray是轮播图数组，最多5个downloadsarray是下载链接数组
详细介绍如何开发一个高性能的下载卡片组件DownloadCard，用于在VitePress中展示资源下载链接。涵盖组件需求分析、Vue3+TypeScript代码实现、组件注册方法、随机马卡龙色背景、按钮文字动态切换、响应式布局与暗色模式适配等核心功能的完整开发流程。下载卡片组件开发组件需求在资源下载页面中，我们需要一个能够集中展示多个下载链接的卡片组件，满足以下需求：支持多个下载链接，每个链接单独显示为一个卡片每个卡片显示：名称、描述、下载按钮根据链接类型动态切换按钮文字（下载/前往）卡片使用随机马卡龙色背景，每次刷新或添加新卡片时颜色不同响应式设计，适配移动端和桌面端悬浮动效提升用户体验组件实现创建文件 docs/.vitepress/theme/components/DownloadCard.vue： 0" class="download-section"> <path fill="currentColor" d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/> {{ item.name }} {{ item.description }} {{ getBtnText(item.url) }} <path fill="currentColor" d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/> 组件注册在 docs/.vitepress/theme/index.ts 中注册组件：import DownloadCard from "./components/DownloadCard.vue"; export default { enhanceApp({ app }) { app.component('DownloadCard', DownloadCard); }, }组件使用在 Markdown 文件中使用：<DownloadCard :downloads="[ { name: 'Github', url: 'https://github.com/xxx/release.zip', description: '官方下载地址，可能需要代理' }, { name: 'Github 加速', url: 'https://gh-proxy.org/https://github.com/xxx/release.zip', description: '使用 Gh Proxy 加速下载' }, { name: '百度网盘', url: 'https://pan.baidu.com/s/xxx?pwd=xxxx', description: '使用百度网盘进行下载，提取码：xxxx' }, { name: 'QQ群', url: 'https://qm.qq.com/q/xxx', description: '加入 QQ 群下载资源' } ]" />关键实现点1. 随机马卡龙色背景通过数组存储多种马卡龙色，使用索引取模实现每个卡片不同的颜色：const macaronColors = [ 'rgba(255, 182, 193, 0.25)', // 粉色 'rgba(173, 216, 230, 0.25)', // 浅蓝色 'rgba(144, 238, 144, 0.25)', // 浅绿色 // ... 更多颜色 ] const getRandomColor = (index: number) => { return macaronColors[index % macaronColors.length] }2. 按钮文字动态切换根据链接类型动态显示不同的按钮文字，QQ链接显示"立即前往"，其他链接显示"立即下载"：const getBtnText = (url: string) => { if (url.includes('qm.qq.com') || url.includes('qq.com')) { return '立即前往' } return '立即下载' }3. 屏蔽链接图标通过 CSS 伪元素 ::before 屏蔽主题自带的链接图标：.download-name, .download-btn { &::before { display: none !important; } }4. 响应式设计使用媒体查询适配移动端：@media (max-width: 640px) { .download-card { padding: 12px 16px; gap: 12px; } .download-icon { width: 40px; height: 40px; } }参数说明参数类型必填说明downloadsDownloadItem[]是下载项数组DownloadItem 类型参数类型必填说明namestring是下载项名称urlstring是下载链接descriptionstring否下载项描述
详细介绍如何开发一个高性能的作者卡片组件AuthorCard，用于在VitePress中展示作者信息。涵盖组件需求分析、Vue3+TypeScript代码实现、组件注册方法、随机马卡龙色背景、插槽传值、响应式布局与暗色模式适配等核心功能的完整开发流程，还包含将长文本内容作为插槽传递以避免特殊字符解析问题的技巧。概述本文介绍如何开发一个美观的作者卡片组件 AuthorCard，用于在 VitePress 中展示作者信息、简介和许可证等内容。组件需求圆角矩形卡片设计左上角作者头像（支持本地图片和图链）作者名点击跳转链接副名称显示（斜体）简介内容（支持多行文本和链接）许可证显示随机马卡龙色渐变背景悬浮动效响应式适配组件代码创建文件 docs/.vitepress/theme/components/AuthorCard.vue： {{ name }} {{ name }} {{ subtitle }} <slot name="description" /> 许可证：{{ license }} 注册组件在 docs/.vitepress/theme/index.ts 中注册组件：import AuthorCard from "./components/AuthorCard.vue"; export default { enhanceApp({ app }: { app: any }) { app.component('AuthorCard', AuthorCard); }, };使用方法基础用法<AuthorCard avatar="/avatar.png" name="作者名称" link="https://example.com" subtitle="副名称" license="MIT" > 这里是多行简介内容 </AuthorCard>完整示例<AuthorCard avatar="/mcoo/avatar.png" name="凉宫山风" link="https://space.bilibili.com/39934370" subtitle="Y_Suzumiya" license="CC BY-NC-SA 4.0" > 来自@方块工程师杯官方 比赛瑞士轮第四轮的赛博马场，快来和xdm来一场紧张刺激的赛马罢* 感兴趣的兄弟们可以进群一起赤石awa~：927868234 ---------------------------- Mcoo服务器基于 Fabric 1.21 的原版生存玩法运行... </AuthorCard>关键实现点1. 使用插槽传递长文本当需要传递包含特殊字符的多行文本时，使用 prop 传值会导致解析错误。解决方案是使用 Vue 插槽： <slot name="description" /> 使用时通过 传递内容：<AuthorCard ...> 多行文本内容... </AuthorCard>2. 随机马卡龙色背景使用 computed 和 Math.random() 实现每次渲染随机选择颜色：const macaronColors = [ { bg: 'rgba(255, 182, 193, 0.25)', bgEnd: 'rgba(255, 182, 193, 0.05)' }, // ... 更多颜色 ] const randomColor = computed(() => { const index = Math.floor(Math.random() * macaronColors.length) return macaronColors[index] })背景使用渐变，从顶部颜色到底部透明：:style="{ background: `linear-gradient(180deg, ${randomColor.bg} 0%, ${randomColor.bgEnd} 100%)` }"3. 屏蔽链接图标由于我们之前为外部链接添加了图标，所以需要通过 CSS 屏蔽：.name { &::before { display: none !important; } }4. 响应式适配使用媒体查询调整移动端样式：@media (max-width: 640px) { .author-card { padding: 12px 16px; gap: 12px; } .avatar { width: 48px; height: 48px; } }组件参数说明参数说明类型默认值avatar头像图片地址string-name作者名称string-link作者链接string#subtitle副名称（斜体）string''license许可证文本string''插槽说明description简介内容，支持 HTML 标签
详细介绍如何开发一个高性能的图片轮播组件ImageGallery，用于在VitePress中展示图片集。涵盖组件需求分析、Vue3+TypeScript代码实现、组件注册方法、响应式布局与暗色模式适配、箭头切换与缩略图导航等核心功能的完整开发流程。概述本文介绍如何开发一个高性能的图片轮播组件 ImageGallery，用于在 VitePress 中展示图片集。组件需求大图展示（圆角矩形，与 BiliVideo 风格一致）底部缩略图列表鼠标悬停大图显示左右箭头切换图片自动缩放填满框支持本地图片和图链轻量快速，不影响加载速度组件代码创建文件 docs/.vitepress/theme/components/ImageGallery.vue： 0" class="image-gallery"> 1" class="arrow arrow-left" :class="{ visible: showArrows }" @click="prev"> <path fill="currentColor" d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/> 1" class="arrow arrow-right" :class="{ visible: showArrows }" @click="next"> <path fill="currentColor" d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/> 注册组件在 docs/.vitepress/theme/index.ts 中注册组件：import ImageGallery from "./components/ImageGallery.vue"; export default { enhanceApp({ app }: { app: any }) { app.component('ImageGallery', ImageGallery); }, };使用方法在 Markdown 文件中使用：<ImageGallery :images="[ { src: '图片1地址.jpg', alt: '图片1' }, { src: '图片2地址.jpg', alt: '图片2' }, { src: '图片3地址.jpg', alt: '图片3' } ]" />关键实现点1. 类型定义使用 TypeScript 接口定义图片数组结构：interface Props { images: { src: string alt?: string }[] }2. 图片填充使用 padding-bottom 百分比实现响应式 16:9 容器：.main-image { padding-bottom: 56.25%; // 16:9 比例 } img { object-fit: cover; // 图片填满容器 }3. 箭头切换使用 v-if 控制箭头显示，通过点击事件切换图片：const showArrows = ref(false) const prev = () => { activeIndex.value = activeIndex.value === 0 ? props.images.length - 1 : activeIndex.value - 1 }4. 暗色模式适配使用 CSS 变量和媒体查询适配暗色模式：@media (prefers-color-scheme: dark) { box-shadow: 0 0 20px rgba(255, 255, 255, 0.1), 0 0 10px rgba(255, 255, 255, 0.2); }
本文详细介绍了如何开发一个更好用的 VitePress 团队页面组件。原生的 VPTeamMembers 组件存在两个痛点：GitHub 头像在国内网络环境下加载缓慢，以及添加链接图标需要编写大段 SVG 代码。通过使用本地资源文件、TypeScript 类型定义和 CSS 悬浮动效，我们开发了一个轻量级、易维护的 TeamMembers 组件。该组件支持灵活的成员管理、多种链接平台图标自动映射，并实现了管理员/普通成员和在职/离职成员的自动分类显示功能。前言在 VitePress 中，官方提供了 VPTeamMembers 组件来展示团队成员。然而在实际使用中，我发现它存在两个明显的痛点：头像加载缓慢 - 直接引用 GitHub 头像源，国内网络环境下经常加载失败或超时添加链接图标繁琐 - 需要手动编写大段 SVG 代码，不仅难以维护，还影响文章可读性为了解决这些问题，我开发了一个更加易用的团队页面组件。实现思路核心目标使用本地头像图片，告别加载慢的问题链接图标也使用本地 SVG 文件支持灵活的成员管理（管理员/普通成员、在职/离职）添加悬浮动效提升视觉体验技术方案创建一个可复用的 Vue 组件 TeamMembers.vue使用 TypeScript 定义成员数据结构通过 props 接收标题、描述和成员列表使用 CSS 实现卡片悬浮效果组件开发目录结构docs/ ├── public/ │ ├── mcoo/ # 成员头像目录 │ │ ├── DoubleSpirit121.png │ │ └── RSEGordon.png │ └── icons/ # 链接图标目录 │ ├── github.svg │ ├── bilibili.svg │ └── ... └── .vitepress/ └── theme/ └── components/ └── TeamMembers.vue组件代码首先创建 TeamMembers.vue 组件： {{ title }} {{ description }} {{ member.name }} {{ member.title }} 样式设计为组件添加悬浮动效和响应式布局：.member-card { border-radius: 12px; background: var(--vp-c-bg-soft); transition: all 0.3s ease; } .member-card:hover { transform: translateY(-4px); box-shadow: 0 8px 30px rgba(var(--vp-c-brand-rgb), 0.15); } .member-card:hover .avatar { transform: scale(1.05); } .member-grid { display: flex; flex-wrap: wrap; justify-content: center; gap: 20px; max-width: 1200px; }全局注册组件在 index.ts 中注册组件，使其可以在 Markdown 文件中直接使用：import TeamMembers from "./components/TeamMembers.vue"; export default { extends: Teek, enhanceApp({ app }: { app: any }) { app.component('TeamMembers', TeamMembers); }, }使用方法准备资源文件将成员头像图片放入 docs/public/mcoo/ 目录将链接图标放入 docs/public/icons/ 目录（GitHub、Bilibili、QQ 等图标已准备）编写团队页面在 Markdown 文件中使用组件：--- title: 团队介绍 permalink: /team layout: page article: false sidebar: false --- Mcoo 墨客小筑 人活一世，草木一秋，开心即可，不必讨好。 <TeamMembers title="核心成员" description="主要维护者和开发者。" :members="teamMembers.filter(m => m.role === 'admin' && m.active !== false)" /> <TeamMembers title="团队成员" description="排名不分先后，感谢以下成员的贡献。" :members="teamMembers.filter(m => m.role === 'member' && m.active !== false)" /> m.active === false)" class="inactive-section"> <TeamMembers title="曾任成员" description="感谢曾经的陪伴。" :members="teamMembers.filter(m => m.active === false)" /> 功能特性支持的链接平台平台参数值图标文件GitHubgithub/icons/github.svg哔哩哔哩bilibili/icons/bilibili.svgQQqq/icons/QQ.svg微信wechat/icons/wechat.svgYouTubeyoutube/icons/youtube.svg微博weibo/icons/weibo.svg爱发电aifadian/icons/aifadian.svg成员角色admin - 核心成员，卡片头像显示为 100pxmember - 普通成员，卡片头像显示为 80px离职成员管理将成员的 active 设为 false，该成员会自动显示在底部的"曾任成员"区域，无需手动移动位置。视觉效果鼠标悬停时卡片微微上浮卡片四周产生辉光效果头像图片放大动画响应式布局适配移动端总结通过使用本地资源，我们解决了 GitHub 头像加载慢的问题；通过图标映射表，我们简化了链接图标的添加方式。这种方案不仅提升了页面加载速度，也让后续维护变得更加简单。添加新成员只需在数组中添加一个对象，无需关心任何样式和布局代码。
为首页特性卡片添加悬停动画效果，增强交互体验。通过 CSS 伪类和变换效果，让首页的 VPFeature 特性卡片在鼠标悬停时产生放大、阴影加深或颜色变化等动画效果，提升用户交互感受和站点的专业度。给首页特性VPFeature加一个hover效果，添加如下代码即可/* .vitepress/theme/style/var.css */ /* VPFeatures 页卡悬浮效果 */ .VPFeatures .items .item { transition: transform 0.3s; } .VPFeatures .items .item:hover { transform: translateY(-5px); }
集成不蒜子统计插件，显示页面浏览量统计信息。不蒜子是一个轻量级的中国本土网站统计工具，相比 Google Analytics 更加简洁，可以显示站点总访问量、页面浏览次数等信息，适合中文站点使用。安装插件pnpm add -D busuanzi.pure.js// .vitepress/theme/index.ts import DefaultTheme from 'vitepress/theme' import { inBrowser } from 'vitepress' import busuanzi from 'busuanzi.pure.js' export default { extends: DefaultTheme, enhanceApp({ app , router }) { if (inBrowser) { router.onAfterRouteChanged = () => { busuanzi.fetch() } } }, }将其放置到团队页面中 本站总访问量 次 本站访客数 人次
集成 Google Analytics 谷歌分析插件，统计网站访问数据。通过 vitepress-plugin-google-analytics 插件，可以在 VitePress 站点中集成 Google Analytics 服务，追踪页面浏览量、用户来源、停留时间等数据。利用插件google-analytics，来查看网站访问量pnpm add -D vitepress-plugin-google-analytics在.vitepress/theme/index.ts中引入// .vitepress/theme/index.ts import DefaultTheme from "vitepress/theme" import googleAnalytics from 'vitepress-plugin-google-analytics' export default { extends: DefaultTheme, enhanceApp({app}) { googleAnalytics({ id: 'G-******', //跟踪ID，在analytics.google.com注册即可 }), }, }
使用记号笔效果，突出显示重要内容。通过自定义 Markdown 插件或 CSS 样式，可以实现类似记号笔的高亮效果，用双等号包裹的文字会显示为醒目的高亮背景色。在某些整段的文字中，我们可以用记号笔，划出重点在theme/style新建marker.css文件. ├─ docs │ ├─ .vitepress │ │ └─ config.mts │ │ └─ theme │ │ └─ style │ │ └─ index.css │ │ └─ marker.css │ └─ index.md └─ node_modules将下面代码，复制粘贴到marker.css中/* .vitepress/theme/style/marker.css */ /* 记号笔 不喜欢可自行调整 */ .marker-text { text-decoration: underline; text-decoration-thickness: 9px; text-decoration-color: rgba(255, 228, 0, 0.4); text-underline-offset: -4px; text-decoration-skip-ink: none; } /* 荧光笔 不喜欢可自行调整*/ .marker-text-highlight { border-radius: 5px 5px; background: transparent; color: var(--vp-c-text-soft); background: linear-gradient(104deg, rgba(130, 255, 173, 0) 0.9%, rgba(130, 255, 173, 1.25) 2.4%, rgba(130, 255, 173, 0.5) 5.8%, rgba(130, 255, 173, 0.1) 93%, rgba(130, 255, 173, 0.7) 96%, rgba(130, 255, 1732, 0) 98%), linear-gradient(183deg, rgba(130, 255, 173, 0) 0%, rgba(130, 255, 173, 0.3) 7.9%, rgba(130, 255, 173, 0) 15%); } /* 尤雨溪 不喜欢可自行调整 */ .marker-evy { white-space: nowrap; position: relative; } .marker-evy:after { content: ''; position: absolute; z-index: -1; top: 66%; left: 0em; right: 0em; bottom: 0; transition: top 200ms cubic-bezier(0, 0.8, 0.13, 1); background-color: rgba(79, 192, 141, 0.5); } .marker-evy:hover:after { top: 0%; }然后在index.css中引入生效/* .vitepress/theme/style/index.css */ @import './marker.css';输入：<sapn class="marker-text">这里是重重点</sapn><sapn class="marker-text-highlight">这里是荧光笔</sapn><sapn class="marker-evy">这里是尤雨溪的主页样式，鼠标放在我上面看效果</sapn>