组件结构
一个项目的功能组件虽然有很多,但是入口组件只有一个,如果您不知道这些功能组件都在哪里执行,不妨从入口组件开始解读,一步一步往下延伸,最终把项目功能吃透。
Teek 在首页、文章页、空白页、全局都写了组件来实现功能,但是这些组件并不是分开引入,而是统一在 Layout
组件里引入,并派发到 VitePress 不同的插槽,如:
vue
<!-- src/layout/index.vue -->
<script setup lang="ts" name="TeekLayout">
import DefaultTheme from "vitepress/theme";
import { useData } from "vitepress";
import {
RightBottomButton,
Notice,
Home,
Footer,
ArticleAnalyze,
Comment,
ArchivesPage,
CataloguePage,
} from "../components";
const { Layout } = DefaultTheme;
const { theme } = useData();
const { teekTheme = true } = theme.value;
// 维护已使用的插槽,防止外界传来的插槽覆盖已使用的插槽
const usedSlots = [
"home-hero-before",
"nav-bar-content-after",
// 其他模板里已使用的插槽 ...
];
</script>
<template>
<template v-if="teekTheme">
<ClientOnly>
<!-- 全局组件 -->
<RightBottomButton />
<Notice />
</ClientOnly>
<Layout :class="ns.b()">
<template #home-hero-before>
<slot name="home-hero-before" />
<ClientOnly>
<!-- 自定义首页 -->
<Home />
</ClientOnly>
</template>
<template #layout-bottom>
<!-- 底部组件 -->
<Footer v-if="isHomePage()" />
<slot name="layout-bottom" />
</template>
<template #doc-before>
<slot name="doc-before" />
<!--文章页信息组件 -->
<ArticleAnalyze />
</template>
<template #doc-after>
<slot name="doc-after" />
<!-- 评论区组件 -->
<Comment />
</template>
<template #page-top>
<slot name="page-top" />
<ArchivesPage />
<CataloguePage />
</template>
<!-- 未使用的其他 VP 插槽 -->
<template
v-for="(_, name) in Object.keys($slots).filter(name => !usedSlots.includes(name))"
:key="name"
#[name]="slotData"
>
<slot :name="name" v-bind="slotData"></slot>
</template>
</Layout>
</template>
<template v-else>
<Layout>
<template v-for="(_, name) in $slots" :key="name" #[name]="slotData">
<slot :name="name" v-bind="slotData"></slot>
</template>
</Layout>
</template>
</template>
目录结构
sh
src
│
├─ components
│ ├─ base # 基础样式组件
│ │
│ ├─ common # 公共组件
│ │ ├─ ArticlePage # 文章页组件
│ │ ├─ Avatar # 头像组件
│ │ ├─ Breadcrumb # 面包屑组件
│ │ ├─ FocusTrap # 聚焦组件
│ │ ├─ icon # 图标组件
│ │ ├─ ImageViewer # 图片查看器组件
│ │ ├─ InputSlide # 滑块组件
│ │ ├─ Message # 消息提示组件
│ │ ├─ HomeCard # 分页卡片组件
│ │ ├─ Pagination # 分页组件
│ │ ├─ Popover # 弹窗组件
│ │ ├─ Segmented # 分段控制器组件
│ │ ├─ TitleTag # 标题标签组件
│ │ ├─ TransitionCollapse # 折叠动画组件
│ │ ├─ VerifyCode # 随机验证码组件
│ │ ├─ VpContainer # VitePress 容器组件
│ │
│ ├─ theme # 主题组件
│ │ ├─ ArchivesPage # 归档页组件
│ │ ├─ ArticleAnalyze # 文章页分析组件
│ │ ├─ ArticleAppreciation # 文章页赞赏组件
│ │ ├─ ArticleBreadcrumb # 文章页面包屑组件
│ │ ├─ ArticleHeadingHighlight # 文章页标题高亮组件
│ │ ├─ ArticleImagePreview # 图片预览组件
│ │ ├─ ArticleInfo # 文章信息组件
│ │ ├─ ArticleOverviewPage # 清单页组件
│ │ ├─ ArticlePageStyle # 文章页样式组件
│ │ ├─ ArticleShare # 文章页分页组件
│ │ ├─ ArticleTitle # 文章标题组件
│ │ ├─ ArticleUpdate # 文章最近更新栏组件
│ │ ├─ BodyBgImage # Body 背景图片组件
│ │ ├─ CataloguePage # 目录页组件
│ │ ├─ CodeBlockToggle # 代码块加强组件
│ │ ├─ CommentArtalk # Artalk 评论区组件
│ │ ├─ CommentGiscus # Giscus 评论区组件
│ │ ├─ CommentTwikoo # Twikoo 评论区组件
│ │ ├─ CommentWaline # Waline 评论区组件
│ │ ├─ ConfigProvider # Teek 入口文件
│ │ ├─ DemoCode # Demo 容器组件
│ │ ├─ FooterGroup # 底部信息组组件
│ │ ├─ FooterInfo # 底部信息组件
│ │ ├─ Home # 首页组件
│ │ ├─ HomeBanner # 首页 Banner 组件
│ │ ├─ HomeCardList # 首页卡片栏组件
│ │ ├─ HomeCategoryCard # 首页分类卡片组件
│ │ ├─ HomeDocAnalysisCard # 首页文章分析卡片组件
│ │ ├─ HomeFriendLinkCard # 首页友情链接卡片组件
│ │ ├─ HomeFullscreenWallpaper # 壁纸模式组件
│ │ ├─ HomeMyCard # 首页我的卡片组件
│ │ ├─ HomePostList # 首页文章列表组件
│ │ ├─ HomeTagCard # 首页标签卡片组件
│ │ ├─ HomeTopArticleCard # 首页置顶文章卡片组件
│ │ ├─ Layout # 布局组件(入口组件)
│ │ ├─ LoginPage # 登录页
│ │ ├─ Notice # 公告组件
│ │ ├─ RightBottomButton # 右下角按钮组组件
│ │ ├─ RiskLinkPage # 风险链接提示页
│ │ ├─ ThemeEnhance # 主题增强面板组件
VitePress 从 src/index.ts
(入口文件)解析 Layout
函数,该函数返回 src/layout.index.vue
组件(入口组件),该入口组件将 Teek 的各个功能组件派发到 VitePress 不同的插槽,最终形成现在的 Teek 主题。
配置项获取
在开发功能组件的时候,Teek 往往不会在组件内部固定功能,而是由用户通过配置项来开关功能。
在 VitePress 中,配置项往往有 2 种方式配置:
.vitepress/config.mts
全局配置- Markdown 的
frontmatter
局部配置
如果 2 种方式都配置,那么 Markdown 的 frontmatter
配置优先级更改,比如 Teek 的评论区功能,用户可以给每一个 Markdown 配置不同的评论区。
配置项获取的例子如:
vue
<script setup lang="ts">
import { computed } from "vue";
import { useData } from "vitepress";
const { theme, frontmatter } = useData();
const commentConfig = computed(() => ({
...theme.comment,
...frontmatter.value.comment,
...frontmatter.value.tk.comment, // 首页 index.md 配置项
}));
</script>
<template></template>
这样编写方式既支持 2 种方式配置,也支持给配置项添加默认值。2 种配置方式如下(index.md
和 文章页.md
是 frontmatter
方式):
ts
// .vitepress/config.mts
import { defineTeekConfig } from "vitepress-theme-teek/config";
const teekConfig = defineTeekConfig({
comment: {
provider: "giscus",
options: {
repo: "your repo",
repoId: "your repoId",
category: "your category",
categoryId: "your categoryId",
}
};
});
yaml
---
tk:
comment:
provider: "giscus"
options:
repo: "your repo"
repoId: "your repoId"
category: "your category"
categoryId: "your categoryId"
---
yaml
---
comment:
provider: "giscus"
options:
repo: "your repo"
repoId: "your repoId"
category: "your category"
categoryId: "your categoryId"
---