--- url: /30.生态/04.主题组件/ArchivesPage 归档页.md --- # ArchivesPage 归档页 ## 基础使用 将归档页注册到全局里: ```ts import DefaultTheme from "vitepress/theme"; import { TkArchivesPage } from "vitepress-theme-teek"; import "vitepress-theme-teek/theme-chalk/tk-archives-page.css"; export default { extends: DefaultTheme, enhanceApp({ app, siteData }) { app.component("TkArchivesPage", TkArchivesPage); }, }; ``` 创建一个 Markdown 文件,在 `frontmatter` 添加如下内容: ```yaml --- layout: TkArchivesPage --- ``` 此时访问该 Markdown 文件,即可看到效果。 --- --- url: /30.生态/04.主题组件/ArticleAnalyze 文章分析.md --- # ArticleAnalyze 文章分析 使用文章分析组件,可以获取文章的创建时间、字数、阅读时间、访问量等信息。 ## 基础使用 ```ts import { h } from "vue"; import DefaultTheme from "vitepress/theme"; import { TkArticleAnalyze, teekConfigContext } from "vitepress-theme-teek"; provide(teekConfigContext, { author: { name: "Teeker", link: "https://github.com/Kele-Bingtang" }, articleAnalyze: { showIcon: true, dateFormat: "yyyy-MM-dd", showAuthor: true, showCreateDate: true, showUpdateDate: false, showCategory: false, showTag: false, }, docAnalysis: { wordCount: true, readingTime: true, }, // ... 更多配置请看配置系列文章 }); export default { extends: DefaultTheme, Layout: () => h(DefaultTheme.Layout, null, { "doc-before": () => h(TkArticleAnalyze), }), }; ``` --- --- url: /30.生态/04.主题组件/ArticleAppreciation 赞赏.md --- # ArticleAppreciation 赞赏 使用赞赏组件可以在文章页使用赞助功能。 ## 文章页底部赞赏 ```ts import { h } from "vue"; import DefaultTheme from "vitepress/theme"; import { TkDocAfterAppreciation, teekConfigContext } from "vitepress-theme-teek"; import "vitepress-theme-teek/theme-chalk/tk-article-appreciation.css"; provide(teekConfigContext, { appreciation: { options: { icon: "weChatPay", // 赞赏图标,内置 weChatPay 和 alipay expandTitle: "打赏支持", // 展开标题,支持 HTML collapseTitle: "下次一定", // 折叠标题,支持 HTML content: ``, // 赞赏内容,支持 HTML expand: false, // 是否默认展开,默认 false // ... 更多配置请看配置系列文章 }, }, }); export default { extends: DefaultTheme, Layout: () => h(DefaultTheme.Layout, null, { "doc-after": () => h(TkDocAfterAppreciation), }), }; ``` ## 大纲栏底部赞赏 ```ts import DefaultTheme from "vitepress/theme"; import { AsideBottomAppreciation, teekConfigContext } from "vitepress-theme-teek"; import { h } from "vue"; provide(teekConfigContext, { appreciation: { options: { title: "打赏支持", // 赞赏标题,支持 HTML content: ``, // 赞赏内容,支持 HTML }, }, }); export default { extends: DefaultTheme, Layout: () => h(DefaultTheme.Layout, null, { "aside-bottom": () => h(AsideBottomAppreciation), }), }; ``` --- --- url: /30.生态/04.主题组件/ArticleBanner 文章页 Banner.md --- # ArticleBanner 文章页 Banner 文章页顶部的 Banner 组件,仅在没有侧边栏的文章页生效,可以添加封面图或者背景色。 ## 基础使用 ```ts import { h } from "vue"; import DefaultTheme from "vitepress/theme"; import { TkArticleBanner, teekConfigContext } from "vitepress-theme-teek"; import "vitepress-theme-teek/theme-chalk/tk-article-update.css"; provide(teekConfigContext, { articleBanner: { enabled: true, // 是否启用单文章页 Banner showCategory: true, // 是否展示分类 showTag: true, // 是否展示标签 defaultCoverImg: "", // 默认封面图 defaultCoverBgColor: "", // 默认封面背景色,优先级低于 defaultCoverImg }, }); // 是否显示 Article Banner(使用条件:开启该功能、没有侧边栏的文章页) const showArticleBanner = computed( () => frontmatter.value.articleBanner !== false && teekConfig.value.articleBanner.enabled && !hasSidebar.value && frontmatter.value.article !== false && (!frontmatter.value.layout || frontmatter.value.layout === "doc") && teekConfig.value.pageStyle === "default" ); export default { extends: DefaultTheme, Layout: () => h(DefaultTheme.Layout, null, { "layout-top": () => (showArticleBanner.value ? h(TkArticleBanner) : null), }), }; ``` --- --- url: /@fragment/coverImg.md --- # ArticleBanner 测试 我是一个测试 `ArticleBanner` 功能的文档,仅在没有侧边栏的文章中出现。 --- --- url: /30.生态/04.主题组件/ArticleHeadingHighlight 标题高亮.md --- # ArticleHeadingHighlight 标题高亮 使用标题高亮组件,可以在点击标题时,高亮标题,方便快速定位在哪个位置。 ## 基础使用 ```ts import { h } from "vue"; import DefaultTheme from "vitepress/theme"; import { TkArticleHeadingHighlight } from "vitepress-theme-teek"; export default { extends: DefaultTheme, Layout: () => h("div", null, [h(TkArticleHeadingHighlight), h(DefaultTheme.Layout)]), }; ``` --- --- url: /30.生态/04.主题组件/ArticleImagePreview 文章页图片预览.md --- # ArticleImagePreview 文章页图片预览 使用文章页图片预览组件可以在文章页进行图片预览。 ## 基础使用 ```ts import { h } from "vue"; import DefaultTheme from "vitepress/theme"; import { TkArticleImagePreview, teekConfigContext } from "vitepress-theme-teek"; provide(teekConfigContext, { appreciation: { article: { imageViewer: { hideOnClickModal: true, // 点击图片时隐藏预览 // ... 更多配置请看配置系列文章 }, }, }, }); export default { extends: DefaultTheme, Layout: () => h(DefaultTheme.Layout, null, { "doc-before": () => h(TkArticleImagePreview), }), }; ``` 更多 `imageViewer` 配置项请看 [ImageViewer 图片预览](/ecosystem/components/image-viewer)。 --- --- url: /30.生态/04.主题组件/ArticleOverviewPage 清单页.md --- # ArticleOverviewPage 清单页 ::: warning 🚧 施工中 很高兴见到你!但很抱歉,这个页面还在施工中,如果没有找到你感兴趣的信息,你可以先在侧边栏的导航中寻找你感兴趣的内容来开始阅读 :::: ## 基础使用 将清单页注册到全局里: ```ts import DefaultTheme from "vitepress/theme"; import { ArticleOverviewPage } from "vitepress-theme-teek"; import "vitepress-theme-teek/theme-chalk/tk-article-overview-page.css"; export default { extends: DefaultTheme, enhanceApp({ app, siteData }) { app.component("TkArticleOverviewPage", ArticleOverviewPage); }, }; ``` 创建一个 Markdown 文件,在 `frontmatter` 添加如下内容: ```yaml --- layout: TkArticleOverviewPage --- ``` 此时访问该 Markdown 文件,即可看到效果。 --- --- url: /30.生态/03.公共组件/ArticlePage 文章页.md --- # ArticlePage 文章页 当在 Markdown 文档将 `frontmatter.layout` 设置为 `page`,VitePress 不会对该 Markdown 生成的文章页应用任何样式,这对于需要创建一个完全自定义的页面时很有用。 **ArticlePage 文章页** 是一个快速构建自定义页面的组件,Teek 提供的 `目录页`、`归档页`、`清单页` 都是基于该组件构建的。 ## 基础用法 ::: demo 构建一个基础的文章页框架 articlePage/basic ::: ## 使用文章页样式 ::: demo 使用 `doc` 配置项来加载 VitePress 的默认文档样式。 ```yaml effect: articlePage/doc-iframe file: articlePage/doc ``` ::: ## 使用大纲栏 ::: demo 当存在 h1 到 h6 标题标签时,可以使用 `aside` 配置项来自动生成一个大纲栏。 ```yaml effect: articlePage/aside-iframe file: articlePage/aside ``` ::: ## API ### 配置项 | 名称 | 说明 | 类型 | 默认值 | | :---- | :-------------------------------------- | :-------- | :----- | | doc | 是否是文档页(使用 VitePress 文档样式) | `boolean` | false | | aside | 是否使用大纲栏 | `boolean` | false | 使用 `aside` 配置项的前提是要有 `h1` 到 `h6` 标题标签,且标题标签里要有 `a` 标签,如: ```vue ``` --- --- url: /30.生态/04.主题组件/ArticlePageStyle 文章页风格.md --- # ArticlePageStyle 文章页风格 使用文章页风格组件可以在文章页进行风格调整。 ## 基础使用 ```ts import { h } from "vue"; import DefaultTheme from "vitepress/theme"; import { TkArticlePageStyle, teekConfigContext } from "vitepress-theme-teek"; import "vitepress-theme-teek/theme-chalk/tk-article-page-style.css"; provide(teekConfigContext, { pageStyle: "default", // 可选 "default" | "card" | "segment" | "card-nav" | "segment-nav",默认为 "default" }); export default { extends: DefaultTheme, Layout: () => h(DefaultTheme.Layout, null, { "doc-before": () => h(TkArticlePageStyle), }), }; ``` --- --- url: /30.生态/04.主题组件/ArticleShare 文章分享.md --- # ArticleShare 文章分享 使用文章分享组件可以分享文章页的链接。 ## 基础使用 ```ts import { h } from "vue"; import DefaultTheme from "vitepress/theme"; import { TkArticleShare, teekConfigContext } from "vitepress-theme-teek"; import "vitepress-theme-teek/theme-chalk/tk-article-share.css"; provide(teekConfigContext, { articleShare: { // ... 更多配置请看配置系列文章 }, }); export default { extends: DefaultTheme, Layout: () => h(DefaultTheme.Layout, null, { "aside-outline-before": () => h(TkArticleShare), }), }; ``` --- --- url: /30.生态/04.主题组件/ArticleUpdate 文章最近更新栏.md --- # ArticleUpdate 文章最近更新栏 在文章页底部使用文章最近更新栏组件,可以显示最近更新的文章信息,方便点击查看。 ## 基础使用 ```ts import { h } from "vue"; import DefaultTheme from "vitepress/theme"; import { TkArticleUpdate, teekConfigContext } from "vitepress-theme-teek"; import "vitepress-theme-teek/theme-chalk/tk-article-update.css"; provide(teekConfigContext, { articleUpdate: { limit: 3, // 默认为 3,表示最多显示 3 条最近更新文章 }, }); export default { extends: DefaultTheme, Layout: () => h(DefaultTheme.Layout, null, { "doc-after": () => h(TkArticleUpdate), }), }; ``` --- --- url: /30.生态/03.公共组件/Avatar 头像.md --- # Avatar 头像 Avatar 组件是基于 ElementPlus 的 Avatar 组件进行二次封装,添加了部分功能。 大部分功能请看 ElementPlus 的 [Avatar 文档](https://element-plus.org/zh-CN/component/avatar.html)。 ## 文本头像 如果是中文,则取第一个字符,如果是一个英文单词,则取前两个转大写,如果是多个英文单词,则取前两个单次的首字母转大写。 ::: demo avatar/text ::: ## 在线 Icon 支持传入在线 Iconify 图标,请前往 [Iconify](https://iconify.design) 寻找您需要的图标。 ::: demo avatar/icon ::: ## API ### 配置项 | 名称 | 说明 | 类型 | 默认值 | | :--------- | :------------------------------------------- | :------------------------------------------------ | :-------------------- | | icon | 设置 Avatar 的图标类型,具体参考 Icon 组件 | `string` / `Component` / `Object` / `IconifyIcon` | — | | icon-size | 图标头像大小 | `string` / `number` | 18 | | size | Avatar 大小 | `number` / `enum` | default | | shape | Avatar 形状 | `enum` | circle | | src | Avatar 图片的源地址 | `string` | — | | src-set | 图片 Avatar 的原生 `srcset` 属性 | `string` | — | | alt | 图片 Avatar 的原生 `alt` 属性 | `string` | — | | fit | 当展示类型为图片的时候,设置图片如何适应容器 | `enum` | cover | | bg-color | 头像背景色 | `string` | `#c0c4cc` / `#6c6e72` | | text-color | 文本头像字体色 | `string` | `var(--vp-c-white)` | | text-size | 文本头像字体大小 | `string` / `number` | 14 | | text | 文本 | `string` | — | ### Events | 名称 | 说明 | 类型 | | :---- | :----------------- | :------------------- | | error | 图片加载失败时触发 | `(e: Event) => void` | ### Slots | 插槽名 | 说明 | | :------ | :----------------- | | default | 自定义头像展示内容 | --- --- url: /10.配置/01.主题配置/10.Banner 配置.md --- # Banner 配置 ## banner 首页 Banner 配置,位于首页顶部。 ::: tip 在首页 `index.md` 的 `frontmatter` 中,`description` 配置项除了 `tk.banner.description` 设置,也可以使用 `tk.description` 设置。 ::: ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ banner: { enabled: true, // 是否启用 Banner name: "Teek", // Banner 标题,默认读取 vitepress 的 title 属性 bgStyle: "fullImg", // Banner 背景风格:pure 为纯色背景,partImg 为局部图片背景,fullImg 为全屏图片背景 pureBgColor: "#28282d", // Banner 背景色,bgStyle 为 pure 时生效 imgSrc: ["/img/bg1.jpg", "/img/bg2.png"], // Banner 图片链接。bgStyle 为 partImg 或 fullImg 时生效 imgInterval: 15000, // 当多张图片时(imgSrc 为数组),设置切换时间,单位:毫秒 imgShuffle: false, // 图片是否随机切换,为 false 时按顺序切换,bgStyle 为 partImg 或 fullImg 时生效 imgWaves: true, // 是否开启 Banner 图片波浪纹,bgStyle 为 fullImg 时生效 mask: true, // Banner 图片遮罩,bgStyle 为 partImg 或 fullImg 时生效 maskBg: "rgba(0, 0, 0, 0.4)", // Banner 遮罩颜色,如果为数字,则是 rgba(0, 0, 0, ${maskBg}),如果为字符串,则作为背景色。bgStyle 为 partImg 或 fullImg 且 mask 为 true 时生效 textColor: "#ffffff", // Banner 字体颜色,bgStyle 为 pure 时为 '#000000',其他为 '#ffffff' titleFontSize: "3.2rem", // 标题字体大小 descFontSize: "1.4rem", // 描述字体大小 descStyle: "types", // 描述信息风格:default 为纯文字渲染风格(如果 description 为数组,则取第一个),types 为文字打印风格,switch 为文字切换风格 description: ["故事由我书写,旅程由你见证,传奇由她聆听 —— 来自 Young Kbt", "积跬步以至千里,致敬每个爱学习的你 —— 来自 Evan Xu"], // 描述信息 switchTime: 4000, // 描述信息切换间隔时间,单位:毫秒。descStyle 为 switch 时生效 switchShuffle: false, // 描述信息是否随机切换,为 false 时按顺序切换。descStyle 为 switch 时生效 typesInTime: 200, // 输出一个文字的时间,单位:毫秒。descStyle 为 types 时生效 typesOutTime: 100, // 删除一个文字的时间,单位:毫秒。descStyle 为 types 时生效 typesNextTime: 800, // 打字与删字的间隔时间,单位:毫秒。descStyle 为 types 时生效 typesShuffle: false, // 描述信息是否随机打字,为 false 时按顺序打字,descStyle 为 types 时生效 }; }); ``` ```yaml [index.md] --- tk: banner: enabled: true, name: Teek, bgStyle: "fullImg" pureBgColor: "#28282d" imgSrc: - /img/bg1.jpg - /img/bg2.jpg imgInterval: 15000 imgShuffle: false mask: true maskBg: "rgba(0, 0, 0, 0.4)" textColor: "#ffffff" titleFontSize: "3.2rem" descFontSize: "1.4rem" descStyle: "types" # description: # 也支持 tk.description # - 故事由我书写,旅程由你见证,传奇由她聆听 —— 来自 Young Kbt # - 积跬步以至千里,致敬每个爱学习的你 —— 来自 Evan Xu switchTime: 4000 switchShuffle: false typesInTime: 200 typesOutTime: 100 typesNextTime: 800 typesShuffle: false description: - 故事由我书写,旅程由你见证,传奇由她聆听 —— 来自 Young Kbt - 积跬步以至千里,致敬每个爱学习的你 —— 来自 Evan Xu --- ``` ```ts [更多配置项] interface Banner { /** * 是否启用 Banner * * @default true */ enabled?: boolean; /** * Banner 标题 * @default 'vitepress 的 title 属性' */ name?: string; /** * Banner 背景风格:pure 为纯色背景,partImg 为局部图片背景,fullImg 为全屏图片背景 * * @default 'default' */ bgStyle?: "pure" | "partImg" | "fullImg"; /** * Banner 背景色。bgStyle 为 pure 时生效 * * @default '#28282d' */ pureBgColor?: string; /** * Banner 图片链接。bgStyle 为 partImg 或 fullImg 时生效 * * @default [] */ imgSrc?: string | string[] | (() => string | string[]); /** * 当多张图片时(imgSrc 为数组),设置切换时间,单位:毫秒,bgStyle 为 partImg 或 fullImg 时生效 * * @default 15000 (15秒) */ imgInterval?: number; /** * 图片是否随机切换,为 false 时按顺序切换,bgStyle 为 partImg 或 fullImg 时生效 * * @default false */ imgShuffle?: boolean; /** * 是否开启 Banner 图片波浪纹,bgStyle 为 fullImg 时生效 * * @default true */ imgWaves?: boolean; /** * Banner 图片遮罩,bgStyle 为 partImg 或 fullImg 时生效 * * @default true */ mask?: boolean; /** * Banner 遮罩颜色,如果为数字,则是 rgba(0, 0, 0, ${maskBg}),如果为字符串,则作为背景色。bgStyle 为 partImg 或 fullImg 且 mask 为 true 时生效 * * @default 'rgba(0, 0, 0, 0.4)' */ maskBg?: string | number; /** * Banner 字体颜色 * * @default ' #ffffff' */ textColor?: string; /** * 标题字体大小 * * @default '3.2rem' */ titleFontSize?: string; /** * 描述字体大小 * * @default '1.4rem' */ descFontSize?: string; /** * 描述信息风格:default 为纯文字渲染风格(如果 description 为数组,则取第一个),types 为文字打印风格,switch 为文字切换风格 * * @default 'default' */ descStyle?: "default" | "types" | "switch"; /** * 描述信息,在首页 index.md 的 frontmatter 中,除了 tk.banner.description 设置,也可以使用 tk.description 设置 * * @default '' */ description?: string | string[]; /** * 描述信息切换间隔时间,单位:毫秒。descStyle 为 switch 时生效 * * @default 4000 (4秒) */ switchTime?: number; /** * 描述信息是否随机切换,为 false 时按顺序切换。descStyle 为 switch 时生效 * * @default false */ switchShuffle?: boolean; /** * 输出一个文字的时间,单位:毫秒。descStyle 为 types 时生效 * * @default 200 (0.2秒) */ typesInTime?: number; /** * 删除一个文字的时间,单位:毫秒。descStyle 为 types 时生效 * * @default 100 (0.1秒) */ typesOutTime?: number; /** * 打字与删字的间隔时间,单位:毫秒。descStyle 为 types 时生效 * * @default 800 (0.8秒) */ typesNextTime?: number; /** * 描述信息是否随机打字,为 false 时按顺序打字,descStyle 为 types 时生效 * * @default false */ typesShuffle?: boolean; /** * Banner 新特性列表 */ features?: { title: string; details?: string; link?: string; image?: string }[]; /** * feature 轮播间隔时间,单位:毫秒。仅在移动端生效(屏幕小于 719px) * * @default 4000 */ featureCarousel?: number; } ``` ::: ## wallpaper 壁纸模式,在首页 **最顶部** 进入全屏后开启,仅当 `banner.bgStyle = 'fullImg'` 或 `bodyBgImg.imgSrc` 存在才生效。 壁纸模式下: * 禁止通过快捷键打开开发者工具 * 禁止通过右键打开浏览器菜单 * 禁止鼠标滚动,页面滚动条会消失 除此之外,你可以通过配置额外隐藏一些元素。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ wallpaper: { enabled: false, // 是否启用壁纸模式 hideBanner: false, // 开启壁纸模式后,是否隐藏 Banner hideMask: false, // 开启壁纸模式后,是否隐藏 Banner 或 bodyBgImage 的遮罩层,则确保 banner.mask 和 bodyBgImage.mask 为 true 才生效 }; }); ``` ```yaml [index.md] --- tk: wallpaper: enabled: false hideBanner: false hideMask: false --- ``` ```ts [更多配置项] interface Wallpaper { /** * 是否启用壁纸模式 * * @default false */ enabled?: boolean; /** * 开启壁纸模式后,是否隐藏 Banner 文字 * * @default false */ hideBanner?: boolean; /** * 开启壁纸模式后,是否隐藏 Banner 或 bodyBgImage 的遮罩层,则确保 banner.mask 和 bodyBgImage.mask 为 true 才生效 * * @default false */ hideMask?: boolean; } ``` ::: 壁纸模式下,会把 `class="tk-wallpaper-outside"` 的元素隐藏,因此在壁纸模式下需要隐藏自定义的元素,可以给 `class` 加上 `tk-wallpaper-outside`。 --- --- url: /30.生态/03.公共组件/Breadcrumb 面包屑.md --- # Breadcrumb 面包屑 更多用法请看 ElementPlus 的 [Breadcrumb 文档](https://element-plus.org/zh-CN/component/breadcrumb.html)。 --- --- url: /30.生态/04.主题组件/CataloguePage 目录页.md --- # CataloguePage 目录页 ## 基础使用 将目录页注册到全局里: ```ts import DefaultTheme from "vitepress/theme"; import { TkCataloguePage } from "vitepress-theme-teek"; import "vitepress-theme-teek/theme-chalk/tk-catalogue-page.css"; export default { extends: DefaultTheme, enhanceApp({ app, siteData }) { app.component("TkCataloguePage", TkCataloguePage); }, }; ``` 创建一个 Markdown 文件,在 `frontmatter` 添加如下内容: ```yaml --- layout: TkCataloguePage path: guide # 扫描的路径,基于 .vitepress 同级目录 desc: 描述 sidebar: false --- ``` 此时访问该 Markdown 文件,即可看到效果。 --- --- url: /30.生态/04.主题组件/CodeBlockToggle 代码块.md --- # CodeBlockToggle 代码块 使用代码块组件对 VitePress 的默认代码块进行样式和功能加强,支持折叠。 ## 基础使用 ```ts import { h } from "vue"; import DefaultTheme from "vitepress/theme"; import { TkCodeBlockToggle, teekConfigContext } from "vitepress-theme-teek"; import "vitepress-theme-teek/theme-chalk/tk-code-block-toggle.css"; provide(teekConfigContext, { codeBlock: { disabled: false, // 是否禁用新版代码块 collapseHeight: 700, // 超出高度后自动折叠,设置 true 则默认折叠,false 则默认不折叠 // ... 更多配置请看配置系列文章 }, }); export default { extends: DefaultTheme, Layout: () => h(DefaultTheme.Layout, null, { "doc-before": () => h(TkCodeBlockToggle), }), }; ``` --- --- url: /30.生态/04.主题组件/评论区/CommentArtalk 评论区.md --- # CommentArtalk 评论区 使用 Artalk 快速搭建一个评论区。 ## 基础使用 ```ts import { h } from "vue"; import DefaultTheme from "vitepress/theme"; import { TkCommentArtalk, teekConfigContext } from "vitepress-theme-teek"; import "vitepress-theme-teek/theme-chalk/tk-comment-artalk.css"; provide(teekConfigContext, { comment: { options: { // artalk 配置,官网:https://artalk.js.org/ server: "https://vp.teek.top", site: "Teek Site", }, }, }); export default { extends: DefaultTheme, Layout: () => h(DefaultTheme.Layout, null, { "doc-after": () => h(TkCommentArtalk), }), }; ``` ## 实例注入 通过配置项 `server`,Teek 内部会自动创建一个 Artalk 实例,当然您也可以手动注入示例: 首先您需要安装 Artalk 依赖: ```bash pnpm add -D artalk ``` 然后引入: ```ts import DefaultTheme from "vitepress/theme"; import { TkCommentArtalk, teekConfigContext, artalkContext } from "vitepress-theme-teek"; import { h } from "vue"; import { useData, useRoute } from "vitepress"; import Artalk from "artalk"; import "artalk/Artalk.css"; import "vitepress-theme-teek/theme-chalk/tk-comment-artalk.css"; export default { extends: DefaultTheme, Layout: defineComponent({ name: "LayoutProvider", setup() { const { isDark, page } = useData(); const route = useRoute(); provide(teekConfigContext, { comment: { options: { // artalk 配置,官网:https://artalk.js.org/ server: "https://vp.teek.top", site: "Teek Site", }, }, }); // options 为 `provide(teekConfigContext, {})` 的内容 provide(artalkContext, (el, options) => Artalk.init({ el, darkMode: isDark.value, pageKey: route.path, pageTitle: page.value.title, server: options.server, site: options.site, }) ); return () => h(DefaultTheme.Layout, null, { "doc-after": () => h(TkCommentArtalk), }); }, }), }; ``` 手动创建实例会更灵活,您可以随意操控实例的样子。 --- --- url: /30.生态/04.主题组件/评论区/CommentGiscus 评论区.md --- # CommentGiscus 评论区 使用 Giscus 快速搭建一个评论区。 ## 基础使用 ```ts import { h } from "vue"; import DefaultTheme from "vitepress/theme"; import { TkCommentGiscus, teekConfigContext } from "vitepress-theme-teek"; import "vitepress-theme-teek/theme-chalk/tk-comment-giscus.css"; provide(teekConfigContext, { comment: { options: { // giscus 配置,官网:https://giscus.app/zh-CN repo: "your repo", repoId: "your repo id", category: "your category", categoryId: "your category id", }, }, }); export default { extends: DefaultTheme, Layout: () => h(DefaultTheme.Layout, null, { "doc-after": () => h(TkCommentGiscus), }), }; ``` ## 实例注入 通过配置项 Teek 内部会自动创建一个 Giscus 实例,当然您也可以手动注入示例: 首先您需要安装 Giscus 依赖: ```bash pnpm add -D @giscus/vue ``` 然后引入: ```ts import DefaultTheme from "vitepress/theme"; import { TkCommentGiscus, teekConfigContext, giscusContext } from "vitepress-theme-teek"; import { h } from "vue"; import Giscus from "@giscus/vue"; import "vitepress-theme-teek/theme-chalk/tk-comment-giscus.css"; export default { extends: DefaultTheme, Layout: defineComponent({ name: "LayoutProvider", setup() { provide(giscusContext, () => Giscus); return () => h(DefaultTheme.Layout, null, { "doc-after": () => h(TkCommentGiscus), }); }, }), }; ``` --- --- url: /30.生态/04.主题组件/评论区/CommentTwikoo 评论区.md --- # CommentTwikoo 评论区 使用 Twikoo 快速搭建一个评论区。 ## 基础使用 ```ts import { h } from "vue"; import DefaultTheme from "vitepress/theme"; import { TkCommentTwikoo, teekConfigContext } from "vitepress-theme-teek"; import "vitepress-theme-teek/theme-chalk/tk-comment-twikoo.css"; provide(teekConfigContext, { comment: { options: { // twikoo 配置,官网:https://twikoo.js.org/ envId: "your envId", link: "https://gcore.jsdelivr.net/npm/twikoo@1.6.42/dist/twikoo.all.min.js", }, }); export default { extends: DefaultTheme, Layout: () => h(DefaultTheme.Layout, null, { "doc-after": () => h(TkCommentTwikoo), }), }; ``` ## 实例注入 通过配置项 `server`,Teek 内部会自动创建一个 Twikoo 实例,当然您也可以手动注入示例: 首先您需要安装 Twikoo 依赖: ```bash pnpm add -D twikoo ``` 然后引入: ```ts import DefaultTheme from "vitepress/theme"; import { TkCommentTwikoo, teekConfigContext, twikooContext } from "vitepress-theme-teek"; import { h } from "vue"; import { useData, useRoute } from "vitepress"; import Twikoo from "twikoo"; import "vitepress-theme-teek/theme-chalk/tk-comment-twikoo.css"; export default { extends: DefaultTheme, Layout: defineComponent({ name: "LayoutProvider", setup() { const { isDark, page } = useData(); const route = useRoute(); provide(teekConfigContext, { comment: { options: { // twikoo 配置,官网:https://twikoo.js.org/ envId: "your envId", }, }, }); // options 为 `provide(teekConfigContext, {})` 的内容 provide(twikooContext, (el, options) => twikoo.init({ ...options, el })); return () => h(DefaultTheme.Layout, null, { "doc-after": () => h(TkCommentTwikoo), }); }, }), }; ``` 手动创建实例会更灵活,您可以随意操控实例的样子。 --- --- url: /30.生态/04.主题组件/评论区/CommentWaline 评论区.md --- # CommentWaline 评论区 使用 Waline 快速搭建一个评论区。 ## 基础使用 ```ts import { h } from "vue"; import DefaultTheme from "vitepress/theme"; import { TkCommentWaline, teekConfigContext } from "vitepress-theme-teek"; import "vitepress-theme-teek/theme-chalk/tk-comment-waline.css"; provide(teekConfigContext, { comment: { options: { // waline 配置,官网:https://waline.js.org/ serverURL: "https://vp.teek.top/", jsLink: "https://unpkg.com/@waline/client@v3/dist/waline.js", cssLink: "https://unpkg.com/@waline/client@v3/dist/waline.css", }, }, }); export default { extends: DefaultTheme, Layout: () => h(DefaultTheme.Layout, null, { "doc-after": () => h(TkCommentWaline), }), }; ``` ## 实例注入 通过配置项 Teek 内部会自动创建一个 Waline 实例,当然您也可以手动注入示例: 首先您需要安装 Waline 依赖: ```bash pnpm add -D @waline/client ``` 然后引入: ```ts import DefaultTheme from "vitepress/theme"; import { TkCommentWaline, teekConfigContext, walineContext } from "vitepress-theme-teek"; import { h } from "vue"; import { init } from "@waline/client"; import "@waline/client/style"; import "vitepress-theme-teek/theme-chalk/tk-comment-waline.css"; provide(teekConfigContext, { comment: { options: { // waline 配置,官网:https://waline.js.org/ serverURL: "https://vp.teek.top/", jsLink: "https://unpkg.com/@waline/client@v3/dist/waline.js", cssLink: "https://unpkg.com/@waline/client@v3/dist/waline.css", }, }, }); export default { extends: DefaultTheme, Layout: defineComponent({ name: "LayoutProvider", setup() { // options 为 `provide(teekConfigContext, {})` 的内容 provide(walineContext, (el, options) => init({ serverURL: options.serverURL!, dark: options.dark, el })); return () => h(DefaultTheme.Layout, null, { "doc-after": () => h(TkCommentWaline), }); }, }), }; ``` --- --- url: /30.生态/01.Components 组件.md --- # Components 组件 Teek 有两大组件类型: * 公共组件 * 主题组件 ## 公共组件 公共组件是一些基础的组件,能够独立使用,在公共组件专题会提供 Demo 使用实例。 ## 主题组件 主题组件是基于 VitePress 主题开发的组件,需要配合 VitePress 使用,因此主题组件专题 仅介绍如何在 VitePress 中引入并使用,当您想在其他 VitePress 主题或 VitePress 默认主题下单独引入 Teek 的部分组件时可以参考。 ::: warning 如果您在 `.vitepress/theme/index.ts` 已经引入 Teek,则无需单独引入主题组件。 ::: 在按需引入主题组件前,您必须先在 `.vitepress/config.mts` 中引入 Teek 的配置加载器。 ```ts {5,8} // .vitepress/config.mts import { defineConfig } from "vitepress"; import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({}); export default defineConfig({ extends: teekConfig, }); ``` Teek 的大部分组件并不是像中后台系统组件一样采用 `props` 来传入配置项,而是通过如下两种方式: 1. 在 `config.mts` 文件通过 `defineTeekConfig({})` 添加组件的配置项 2. 在入口组件通过 `provide(teekConfigContext, {})` 添加组件的配置项,`provide` 方式在主题组件的文章里会进行说明 `provide` 方式优先级大于 `defineTeekConfig` 方式。 `defineTeekConfig` 函数内部会进行一些 Vite 插件的初始化,有关 Vite 插件的介绍和如何禁用请看 [Vite 插件](/guide/plugins)。 除此之外,`defineTeekConfig` 函数会注册 Teek 内置的 `Markdown` 拓展,有关 `Markdown` 拓展的介绍请看 [Markdown 拓展](/guide/markdown)。 ::: tip 本专题仅介绍如何引入 Teek 的主题组件,每个组件所需要的配置项请看导航栏 配置 的 主题配置。 ::: 在按需注册主题组件的时候,如果您认为主题组件插入插槽的位置不符合期望,可以阅读 [插槽布局](https://vp.teek.top//guide/slot),选择一个合适的插槽位置。 --- --- url: /30.生态/20.Composables 函数.md --- # Composables 函数 Teek 提供了 Composables 函数(即 Hooks 函数),提高开发效率。 ## onClickOutside 监听点击外部事件,当点击到指定元素外部时,执行回调函数。 ```vue ``` ## useAnchorScroll 监听浏览器滚动,当滚动到锚点,自动在 URL 后面添加锚点信息。 ```ts import { useAnchorScroll } from "vitepress-theme-teek"; const { startWatch } = useAnchorScroll(); const stop = startWatch(); // 开始监听 stop(); // 停止监听 ``` ## useUvPv 使用 busuanzi、vercount 等网站流量统计提供商统计网站访问量。 ```ts import { useUvPv } from "vitepress-theme-teek"; /** * 使用网站流量统计器统计网站访问量 * * @param immediate 是否初始化请求,即自动执行一次 request,类型 boolean * @param options 额外配置项 * * @returnParam sitePv 网站总访问量,类型 number * @returnParam siteUv 网站总访客数,类型 number * @returnParam pagePv 当前页面访问量,类型 number * @returnParam isGet 是否已经获取过数据,类型 boolean * @returnParam request 请求网站流量统计器函数,类型 Function */ const { sitePv, siteUv, pagePv, isGet, request } = useUvPv(true, { url: "", // 如果基于提供商自建个人的网络流量计时器,则请填写对应网址 provider: "busuanzi", // 支持 busuanzi、vercount tryRequest: false, // 如果请求接口失败,是否重试,类型 boolean tryCount: 5, // 重试次数,仅当 tryRequest 为 true 时有效 tryIterationTime: 2000, // 重试间隔时间,单位毫秒,仅当 tryRequest 为 true 时有效 }); ``` ## useClipboard 复制文本到剪贴板。 ```ts import { useClipboard } from "vitepress-theme-teek"; /** * 复制文本到剪贴板 * * @returnParam copy 复制文本到剪贴板,类型 Function * @returnParam text 已复制的文本,类型 string * @returnParam copied 复制是否成功,类型 boolean * @returnParam isSupported 浏览器是否支持复制,类型 boolean */ const { copy, text, copied, isSupported } = useClipboard(); if (!isSupported) alert("您的浏览器不支持复制"); copy("Hello World"); if (copied) alert("复制成功,内容为:" + text); else alert("复制失败"); ``` ## useDebounce 防抖函数。 ```ts import { useDebounce } from "vitepress-theme-teek"; /** * 防抖函数 * * @param func 回调函数 * @param delay 延迟时间 * @param immediate 是否立即执行,如果为 true,则立即执行回调函数,否则在延迟时间后执行 */ const handleClick = useDebounce(() => {}, 500, true); ``` ## useElementHover 监听鼠标在指定元素的悬停状态。 ```vue ``` ## useEventListener 在 `onMounted` 监听事件,在 `onUnmounted` 取消监听事件 ```ts import { useEventListener } from "vitepress-theme-teek"; // 基本使用 useEventListener(window, "click", event => {}); // 函数式传入元素 useEventListener( () => window, "click", event => {} ); ``` ## useLocale 实现国际化功能,获取不同语言下的指定值。 ```ts import { useLocale } from "vitepress-theme-teek"; const { lang, locale, t } = useLocale(); console.log(lang.value); // 当前使用的语言 console.log(locale.value); // 语言配置内容 console.log(t("tk.home.label")); // 获取当前语言的指定内容 ``` 利用 `t` 函数除了直接指定内容外,还可以在获取的同时进行动态赋值。 假如 `zh-CN` 语言配置内容为: ```ts export default { lang: "zh-CN", tk: { pagination: { total: "共 {total} 条", }, }, }; ``` 对 total 赋予真正的值: ```ts import { useLocale } from "vitepress-theme-teek"; const { t } = useLocale(); console.log(t("tk.pagination.total", { total: 20 })); // 输出:共 20 条 ``` ## useMediaQuery 监听媒体查询,可以检查查询结果或在结果更改时接收通知。 ```ts import { useMediaQuery } from "vitepress-theme-teek"; const isLargeScreen = useMediaQuery("(min-width: 1024px)"); // true const isMiniScreen = useMediaQuery("(max-width: 1px)"); // false ``` ## useMounted 创建一个用于在组件挂载时执行的函数。 ```ts import { useMounted } from "vitepress-theme-teek"; useMounted(() => {}); ``` 获取是否通过已挂载阶段的状态: ```ts import { useMounted } from "vitepress-theme-teek"; const isMounted = useMounted(); ``` 这本质上是以下内容的简写: ```ts const isMounted = ref(false); onMounted(() => { isMounted.value = true; }); ``` ## useNamespace 创建一个命名空间,用于创建具有唯一前缀的类名。 ```ts import { useNamespace } from "vitepress-theme-teek"; /** * 命名空间 * * @param block 块名,类型 string * @param namespaceOverrides 命名空间,类型 string */ const ns = useNamespace("button", "tk"); ns.b(); // 返回 "tk-button" ns.e("primary"); // 返回 "tk-button__primary" ns.m("disabled"); // 返回 "tk-button--disabled" ns.be("primary", "disabled"); // 返回 "tk-button-primary__disabled" ns.bm("primary", "disabled"); // 返回 "tk-button-primary--disabled" ns.em("primary", "disabled"); // 返回 "tk-button__primary--disabled" ns.bem("primary", "large", "disabled"); // 返回 "tk-button-primary__large--disabled" ns.is("disabled"); // 返回 "is-disabled" ns.join("select"); // 返回 "tk-select" ns.cssVar("color"); // 返回 "var(--tk-color)" ns.cssVarName("color"); // 返回 "--tk-color" ns.createBem("tk", "button", "primary", "large", "disabled"); // 返回 "tk-button-primary__large--disabled" ``` ## usePopoverSize 获取弹框的位置:`top`、`right`、`bottom`、`left`。 ```vue ``` 计算出来的弹框位置是基于 body 位置进行计算的,所以需要将弹框元素移到 body 元素下。 ## useStorage 创建一个用于管理存储的函数,根据传入的存储类型(sessionStorage 或 localStorage)返回相应的操作函数 ```ts import { useStorage } from "vitepress-theme-teek"; /** * 创建一个用于管理存储的函数,根据传入的存储类型(sessionStorage 或 localStorage)返回相应的操作函数 * * @param type 存储类型,默认为 sessionStorage */ const localStorage = useStorage("localStorage"); localStorage.setStorage("key", "value"); localStorage.getStorage("key"); localStorage.removeStorage("key"); localStorage.removeStorages(["key1", "key2"]); localStorage.clear(["key"]); // 清空除了 key 的其他所有数据 ``` 存储格式: ```json { "_type": "", // 存储值的类型,如 String、Number 等 "value": "" // 存储的值 } ``` ## useScrollData 定时对数据进行截取,实现滚动。 ```ts import { useScrollData } from "vitepress-theme-teek"; import { onMounted } from "vue"; const data = [ { name: "张三", age: 18 }, { name: "李四", age: 19 }, { name: "王五", age: 20 }, { name: "赵六", age: 21 }, { name: "钱七", age: 22 }, { name: "孙八", age: 23 }, { name: "周九", age: 24 }, ]; /** * 定时对数据进行截取,实现滚动 * * @param data 数据,类型 Array * @param limit 显示数量,类型 number * @param options 配置项,类型 UseScrollDataOptions * * @returnParam data 显示的数据,类型 Array * @returnParam start 开始滚动,类型 Function * @returnParam stop 停止滚动,类型 Function * @returnParam restart 重启滚动,类型 Function */ const { data, start, stop, restart } = useScrollData(dataList, 5, {} /* option */); onMounted(() => { start(); stop(); stop(true); // 还原数据为开始状态,当调用 start(),则会从开始状态开始执行,默认 true restart(); }); ``` `option` 类型: ```ts interface UseScrollDataOptions { /** * 自动滚动间隔时间 * * @default 3000 */ intervalTime?: number; /** * data 发生变化,是否重新加载 * * @default false */ reloadWhenDataChanged?: boolean; } ``` ## useSwitchData 从数据列表里按顺序/随机获取一笔数据。 ```ts import { useSwitchData } from "vitepress-theme-teek"; import { onMounted } from "vue"; const dataArray = ["./img1.png", "./img2.png", "./img3.png"]; /** * 从数据列表里按顺序/随机获取一笔数据 * * @param dataList 数据列表,类型 Array * @param option 配置项,类型 UseSwitchDataOption * * @returnParam data 当前数据,类型 Ref * @returnParam index 当前数据的索引,类型 Ref * @returnParam start 开始数据切换,类型 Function * @returnParam stop 停止数据切换,类型 Function * @returnParam restart 重启数据切换,类型 Function */ const { data, index, start, stop, restart } = useSwitchData(dataList, {} /* option */); onMounted(() => { start(); stop(); stop(true); // 还原数据为开始状态,当调用 start(),则会从开始状态开始执行,默认 true restart(); }); ``` `option` 类型: ```ts interface UseSwitchDataOption { /** * 切换间隔时间,单位:毫秒 */ timeout?: number; /** * 是否随机切换数据 */ shuffle?: boolean; /** * data 发生变化,是否重新加载 * * @default false */ reloadWhenDataChanged?: boolean; /** * 切换数据之前执行的回调函数 */ onBeforeUpdate?: (newValue: string) => void; /** * 自定义切换逻辑 */ onUpdate?: (data: Ref, newValue: string) => void; /** * 切换数据之后执行的回调函数 */ onAfterUpdate?: (newValue: string) => void; } ``` ## useTextTypes 打字功能 ```ts import { useTextTypes } from "vitepress-theme-teek"; import { onMounted } from "vue"; const textArray = ["Hello Teek!", "Hello VitePress!", "Hello World!"]; /** * 打字功能 * @param textArray 打字数组 * @param option 打字配置项 * * @returnParam text 当前打字内容 * @returnParam isFinished 打字是否结束 * @returnParam start 开始打字 * @returnParam stop 停止打字 * @returnParam restart 重启打字,类型 Function */ const { text, isFinished, start, stop, restart } = useTextTypes(textArray, {} /* option */); onMounted(() => { start(); stop(); stop(true); // 还原数据为开始状态,当调用 start(),则会从开始状态开始执行,默认 true restart(); }); ``` `option` 类型: ```ts interface TypesOption { /** * 打字间隔时间,单位:毫秒 */ inputTime?: number; /** * 删字间隔时间,单位:毫秒 */ outputTime?: number; /** * 获取新数据间隔时间,单位:毫秒 */ nextTime?: number; /** * 是否随机获取新数据 */ shuffle?: boolean; /** * data 发生变化,是否重新加载 * * @default false */ reloadWhenDataChanged?: boolean; } ``` ## useThemeColor 根据传入的颜色计算其他类似的颜色,然后将计算好的颜色覆盖 VitePress 的 Var 变量。 ```ts import { useThemeColor } from "vitepress-theme-teek"; import { ref } from "vue"; const primary = ref("#395AE3"); // 初始化时已调用 start,无需再次调用 start const { start, stop, update, clear } = useThemeColor(primary); // 修改值后自动重新计算(内部调用 update 函数) primary.value = "#395AE3"; ``` ## useWindowSize 实时获取窗口大小。 ```ts import { useWindowSize } from "vitepress-theme-teek"; import { watch } from "vue"; // 使用方式 1:watch 监听 const { width, height } = useWindowSize(); watch(width, newValue => {}); watch(height, newValue => {}); // 使用方式 2:函数回调监听 useWindowSize((width, height) => {}); // 选项 const { width, height } = useWindowSize(null, { type: "outer", // 获取 outerWidth、outerHeight,默认为 inner // ... }); ``` ## useViewTransition 使用暗色、浅色切换的过渡动画。 ```ts import { useViewTransition } from "vitepress-theme-teek"; useViewTransition({ enabled: true, // 是否启用深浅色切换动画效果 mode: "out-in", // 动画模式,out 始终从点击点往全屏扩散,out-in 第一次从点击点往全屏扩散,再次点击从全屏回到点击点 duration: 300, // 动画持续时间,当 mode 为 out 时,默认为 300ms,mode 为 out-in 时,默认为 600ms easing: "ease-in", // 缓动函数 }); ``` 需要引入 CSS 来实现过渡动画: ```css ::view-transition-old(root), ::view-transition-new(root) { animation: none; mix-blend-mode: normal; } // 当动画模式 mode 为 out-in 时,需要设置 z-index html[view-transition="out-in"] { &::view-transition-old(root), &.dark::view-transition-new(root) { z-index: 1; } &::view-transition-new(root), &.dark::view-transition-old(root) { z-index: 9999; } } ``` ## useVpRouter 绑定自定义函数到 Router 的钩子里,为了防止覆盖掉其他人已添加在 Router 钩子的逻辑,useVpRouter 不是直接覆盖,而是追加。 ```ts import { useVpRouter } from "vitepress-theme-teek"; /** * 绑定自定义函数到 Router 的钩子里 * * @returnParam router Vue Router 实例 * @returnParam route Vue Router 路由实例 * @returnParam bindBeforeRouteChange 绑定自定义函数到 onBeforeRouteChange 钩子 * @returnParam bindBeforePageLoad 绑定自定义函数到 onBeforePageLoad 钩子 * @returnParam bindAfterPageLoad 绑定自定义函数到 onAfterPageLoad 钩子 * @returnParam bindAfterRouteChange 绑定自定义函数到 onAfterRouteChange 钩子 * @returnParam bindRouterFn 自定义绑定逻辑 */ const { router, route, bindBeforeRouteChange, bindBeforePageLoad, bindAfterPageLoad, bindAfterRouteChange, bindRouterFn, } = useVpRouter(); /** * 绑定自定义函数到 onBeforeRouteChange 钩子 * * @param stateFlag 为了防止重复添加,useVpRouter 会在 Router 中添加一个 state 对象,里面维护各个绑定自定义函数的唯一标识,防止重复绑定。 * @remark 什么时候重复添加?当 useVpRouter 在某个组件使用,且组件会重新渲染时,如 404 组件。 * * @param bindFn 要绑定的自定义函数 * @param bindPosition 绑定的位置,before 为在原函数之前绑定,after 为在原函数之后绑定 */ bindBeforeRouteChange("permalink", () => {}, "after"); ``` ## useZIndex 获取一个唯一的 z-index 值。 ```ts import { useZIndex } from "vitepress-theme-teek"; const { currentZIndex, nextZIndex } = useZIndex(); nextZIndex(); // currentZIndex 递增 ``` `currentZIndex` 是一个全局的值,当任意组件调用 `nextZIndex` 时,所有组件获取的 `currentZIndex` 都会递增。 一般用于弹框、提示等悬浮组件,避免 z-index 冲突。 ## useWindowTransition 指定元素出现在屏幕内时,开启过渡效果。 ```ts import { useViewTransition } from "vitepress-theme-teek"; /** * 指定元素出现在屏幕内时,开启过渡效果 * * @param htmlElement 要添加过渡效果的元素,支持数组(支持响应式变量) * @param immediate 是否立即监听元素,如果为 false,则需要手动调用返回的 start 函数,默认 true * * @returnParam start 开启监听元素进入屏幕时开启过渡效果 * @returnParam stop 停止监听元素进入屏幕时开启过渡效果 * @returnParam restart 重启监听元素进入屏幕时开启过渡效果 */ const { start, stop, restart } = useWindowTransition(htmlElement, immediate); ``` --- --- url: /30.生态/04.主题组件/DemoCode 组件预览.md --- # DemoCode 组件预览 使用组件预览组件可以渲染一个 Vue 组件的效果,并支持代码复制、查看源代码等功能。 ## 基础使用 ```ts import { h } from "vue"; import DefaultTheme from "vitepress/theme"; import { TkDemoCode, teekConfigContext } from "vitepress-theme-teek"; import "vitepress-theme-teek/theme-chalk/tk-demo-code.css"; provide(teekConfigContext, { markdown: { demo: { playgroundUrl: "", // Playground 链接 playgroundMainFileName: "App.vue", // Playground 主文件名 githubUrl: "", // Github 链接 playgroundButtonTip: "在 Playground 中编辑", // 鼠标悬浮 Playground 按钮提示 githubButtonTip: "在 Github 中编辑", // 鼠标悬浮 Github 按钮提示 copyButtonTip: "复制代码", // 鼠标悬浮复制代码按钮提示 collapseSourceButtonTip: "查看源代码", // 鼠标悬浮查看源代码按钮提示 expandSourceButtonTip: "隐藏源代码", // 鼠标悬浮隐藏源代码按钮提示 // ... 更多配置请看配置系列文章 }, }, }); export default { extends: DefaultTheme, enhanceApp({ app, siteData }) { app.component("TkDemoCode", TkDemoCode); }, }; ``` ## 插槽 DemoCode 组件默认有 4 个按钮,如果需要自定义按钮,可以通过 `slots` 来实现。 * `teek-demo-code-button-left`:最左侧按钮插槽 * `teek-demo-code-button-right`:最右侧按钮插槽 `app.component` 注册组件时,同名的组件会被覆盖,因此无论 Teek 之前是否已经注册(全局引入时自动注册)过 `TkDemoCode` 组件,您都可以通过 `app.component` 来覆盖。 --- --- url: /30.生态/04.主题组件/FooterGroup 信息组.md --- # FooterGroup 信息组 使用信息组组件可以在页脚中展示多个分组链接。 ## 基础使用 ```ts import { h } from "vue"; import DefaultTheme from "vitepress/theme"; import { TkFooterGroup, teekConfigContext } from "vitepress-theme-teek"; import "vitepress-theme-teek/theme-chalk/tk-footer-group.css"; provide(teekConfigContext, { footerGroup: [ { title: "外部链接", links: [ { name: "示例 1", link: "https://vp.teek.top" }, { name: "示例 2", link: "https://vp.teek.top" }, { name: "示例 3", link: "https://vp.teek.top" }, ], }, { title: "内部链接", links: [ { name: "快速开始", link: "/guide/quickstart" }, { name: "配置简介", link: "/reference/config" }, ], }, ], // ... 更多配置请看配置系列文章 }); export default { extends: DefaultTheme, Layout: () => h(DefaultTheme.Layout, null, { "layout-bottom": () => h(TkFooterGroup), }), }; ``` --- --- url: /30.生态/04.主题组件/FooterInfo 页脚.md --- # FooterInfo 页脚 使用页脚组件可以在页脚自定义内容,如版权信息、备案信息等。 ## 基础使用 ```ts import { h } from "vue"; import DefaultTheme from "vitepress/theme"; import { TkFooterInfo, teekConfigContext } from "vitepress-theme-teek"; import "vitepress-theme-teek/theme-chalk/tk-footer-info.css"; provide(teekConfigContext, { footerInfo: { topMessage: ["下面的内容和图标都可以修改(本条内容也可以隐藏的)"], bottomMessage: ["上面的内容和图标都可以修改(本条内容也可以隐藏的)"], copyright: { createYear: 2021, suffix: "天客 Blog", }, icpRecord: { name: "桂ICP备2021009994号", link: "http://beian.miit.gov.cn/", }, customHtml: `自定义标签内容`, // ... 更多配置请看配置系列文章 }, }); export default { extends: DefaultTheme, Layout: () => h(DefaultTheme.Layout, null, { "layout-bottom": () => h(TkFooterInfo), }), }; ``` --- --- url: /01.指南/10.使用/07.Frontmatter 拓展.md --- # Frontmatter 拓展 ## 什么是 Frontmatter `Frontmatter` 是 YAML 格式的 Markdown 文件头,如: ```markdown --- title: Frontmatter 拓展 date: 2025-09-13 18:35:12 permalink: /guide/frontmatter --- ## 什么是 Frontmatter ``` `---` 之间的语法,就是 `Frontmatter`。通过 `Frontmatter` 可以给 Markdown 文件添加元数据,如:标题、作者、日期、链接等等。 如果只是单纯查看 Markdown 文件,`Frontmatter` 的作用仅仅是添加标识,并没实际作用,但是在某些主题、框架、工具库中,`Frontmatter` 的作用就变得很重要了,部分的主题、框架、工具库会根据 `Frontmatter` 的内容,进行一些特殊处理或开启特殊功能,如 Teek 的 `title` 配置代表给该文件添加一个一级标题,在启动 Teek 后,文章页的一级标题会变成 `title` 的值。 ## Frontmatter 拓展 Teek 提供了丰富的 `Frontmatter` 配置,如常用的 `title`、`date`、`permalink`、`categories` 等,具体参阅 [Frontmatter 配置](/reference/frontmatter.html#文章配置)。 部分 `Frontmatter` 配置可以极大的改善网站的访问体验,但是每次新增一个 Markdown 文件,都要手动添加 `Frontmatter` 配置,非常麻烦。 因此 Teek 提供了自动生成 `Frontmatter` 的功能,当新建了一个 Markdown 文件,并启动项目时,Teek 会给所有没有 `Frontmatter` 的 Markdown 文件自动添加一些 Teek 内置的 `Frontmatter` 配置。 `Frontmatter` 自动生成功能,会直接修改 Markdown 文档的 `frontmatter`,因此为了安全性考虑,默认是关闭的,如果希望开启,进行如下配置: ```ts {5} import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { autoFrontmatter: true, }, }); ``` 如果开启了该功能,那么 Teek 将会对所有 Markdown 文档的 `frontmatter` 添加如下格式: ```yaml --- title: getting date: 2025-03-03 00:45:16 permalink: /pages/eb8f2f categories: - guide --- ``` * `title` 为文章的标题 * `date` 为文章的创建时间 * `permalink` 为文章的永久链接,采用随机数确保唯一 * `categories` 为文章的分类,根据目录层级获取 ::: tip Teek 不会修改已经存在的数据,判断的规则是比较 key,不比较 value。 ::: 开启自动生成 `Frontmatter` 的功能后,可以通过 `autoFrontmatterOption` 来进行部分配置。 ## 取消 categories 自动生成 如果您不希望自动生成 `categories`,则将进行如下配置: ```ts {7} import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { autoFrontmatter: true, autoFrontmatterOption: { categories: false, }, }, }); ``` ## permalink 配置 这是本文主要的介绍内容。 `permalink` 配置,可以自定义文章的永久链接。关于 `permalink` 的具体介绍,请参阅 [永久链接](/guide/permalink),接下来的内容是介绍 `permalink` 的自动生成功能。 ### 关闭 permalink 自动生成 如果您不希望自动生成 `permalink`,则将进行如下配置: ```ts {7} import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { autoFrontmatter: true, autoFrontmatterOption: { permalink: false, }, }, }); ``` ### permalink 生成规则 Teek 生成 `permalink` 的规则有两个: * `simple` 规则:该规则的生成格式是 `/pages/{随机六位数}`,当你第一次开启 `Frontmatter` 自动生成功能时,就会看到该规则生成的 `permalink` * `rules` 规则:该规则需要您完全自定义 `permalink` 的生成格式,相较于 `simple` 规则,该规则的生成格式更灵活,但是需要您自己进行配置 为了兼容 `rewrites` 模式,Teek 根据 `vitePlugins.sidebarOption.resolveRule` 的内容来进行动态判断,你可以在 [永久链接](/guide/permalink#侧边栏方式) 来了解 `resolveRule` 配置是做什么的。 * 当 `vitePlugins.sidebarOption.resolveRule` 为 `filePath` 则 `permalink` 生成规则默认为 `simple` * 当 `vitePlugins.sidebarOption.resolveRule` 为 `rewrites` 则 `permalink` 生成规则默认为 `rules` 默认情况下,`vitePlugins.sidebarOption.resolveRule` 为 `filePath`,因此您可以认为 `permalink` 默认生成规则是 `simple`。 除了动态判断决定默认值之外,您可以强制指定 `permalink` 的生成规则,这样不会受到 `resolveRule` 配置的影响: ```ts {7} import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { autoFrontmatter: true, autoFrontmatterOption: { permalinkType: "rules", // 可选:simple | rules }, }, }); ``` #### simple 规则 (1)默认情况下、(2)手动式设置 `permalinkType` 为 `simple`、(3)`permalinkType` 为 `simple` 时,这任意 3 个方式会开启 `simple` 规则。 `simple` 规则的 `permalink` 生成格式是 `/pages/{随机六位数}`。 如果您不希望以 `/pages` 开头,则自定义一个前缀: ```ts {7} import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { autoFrontmatter: true, autoFrontmatterOption: { permalinkPrefix: "pages", // 默认为 pages,可以修改为自定义值 }, }, }); ``` #### rules 规则 当手动式设置 `permalinkType` 为 `rules` 或 `vitePlugins.sidebarOption.resolveRule` 为 `rewrites` 时,会开启 `rule` 规则。 `rule` 规则允许您自定义 `permalink` 的生成格式,格式如下: ```ts {8-15} import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { autoFrontmatter: true, autoFrontmatterOption: { permalinkType: "rules", permalinkRules: [ { folderName: "01.guide", rule: "/$path/$uuid6" }, // 使用一级目录的哈希混合随机数,$path 最终等于 guide { folderName: "10.配置/01.主题配置", rule: "/reference/$uuid6" }, // 使用混合固定字符串和随机数 { folderName: "15.主题开发", rule: "/willRemove/develop/$uuid6", removeLevel: 1 }, // 先移除一层前缀,再添加前缀,等价于 /develop/$uuid6 { folderName: "20.资源", rule: "/test-$uuid4-$uuid2/aaa/" }, // 使用混合固定字符串和随机数 { folderName: "30.生态", rule: "/$path-$uuid2/teek/$uuid" }, // 使用一级目录的哈希混合随机数 // { folderName: "*" }, // '*' 代表所有文件都生成永久链接,不设置 rule 则默认为 /$path/$uuid6 ], }, }, }); ``` `permalinkRules` 是一个数组,数组的每一项都是一个对象,对象包含 3 个属性: **folderName** * 类型:`string` * 默认值:undefined 一级目录名称,一级目录名称必须与 Markdown 文件所在一级目录名称一致,如果为 `*` 则代表所有一级目录。 **rule** * 类型:`string` * 默认值:`/$path/$uuid6` 指定 `permalink` 生成格式,除了固定的字符串还支持 2 个变量: > `$path{num}` 生成一个 `6-10` 长度的哈希值,根据 Markdown 文件所在一级目录名进行哈希处理得到的哈希值,`{num}` 则可以指定哈希值的长度,不指定 `{num}` 时默认为 6,如文件路径为 `/01.指南/01.简介.md`,则 `$path` 为 `01.指南` 的哈希值。 如果 Markdown 文件所在一级目录名为英文,则 `$path` 为不会进行哈希处理,直接以目录名作为 `$path` 的值(支持 「序号.」 开头)。 > `$uuid{num}` 生成一个 `1-15` 长度的随机字符串,`{num}` 则可以指定随机字符串的长度,不指定 `{num}` 时默认为 6。 **removeLevel** * 类型:`number` * 默认值:`0` 要移除的前缀层级(以 / 分割),如 `permalink` 为 `/test/xx` 时,`removeLevel` 为 1,则最终生成的 `permalink` 为 `/xx`,当 `removeLevel` 为 99,则会移除所有层级,只剩根路径。 ## 生成文章列表封面图 在 `post.defaultCoverImg` 配置项提供封面图链接数组,Teek 在页面加载时会给每一个文章列表随机选择一个封面图,但是这是隐形且有随机性,您无法直观的查看某一个文章列表的封面图链接,因此可以用 `Frontmatter` 自动生成封面图链接功能。 自动生成封面图链接本质上就是在 `Frontmatter` 中添加 `coverImg` 属性,而 `coverImg` 属性值需要您提供一个封面图链接数组。 ```ts {7-8} import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { autoFrontmatter: true, autoFrontmatterOption: { coverImg: true, // 开启自动生成封面图链接功能 coverImgList: ["https://a", "https://b"], // 封面图链接数组 }, }, }); ``` 这样 Teek 会给每一个文章随机从 `coverImgList` 取出一个链接,在 `Frontmatter` 中添加 `coverImg` 键值。 默认情况下,如果 Markdown 文件的 `Frontmatter` 已经存在 `coverImg` 属性,则不会重新生成,但是当更新了 `coverImgList` 后,希望 `coverImg` 的属性值重新生成,那么有 2 种方式达到目的: 1. 先删除 `coverImg` 属性,再重新运行项目生成,如果认为每个 Markdown 文件删除 `coverImg` 属性麻烦,则可以参阅下面的 [删除部分属性](#删除部分属性) 内容进行一次性全部删除 2. 设置 `forceCoverImg` 配置项为 `true` 来开启强制重新生成 `coverImg` 的属性值。 ```ts {8} import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { autoFrontmatter: true, autoFrontmatterOption: { coverImg: true, // 开启自动生成封面图链接功能 forceCoverImg: true, // 强制重新生成 coverImg 的属性值 coverImgList: ["https://a", "https://b"], // 封面图链接数组 }, }, }); ``` ::: warning 一旦重新生成后,请将 `forceCoverImg` 配置项设置为 `false` 或者去掉,否则每次启动项目都会重新生成 `coverImg` 的属性值。 ::: ## 删除部分属性 如果您想删除部分 `Frontmatter` 的属性,可以使用 `transform` 函数来实现,如清空 `permalink` 配置: ```ts {7-10} import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { autoFrontmatter: true, autoFrontmatterOption: { transform: frontmatter => { // 清空 permalink 属性 delete frontmatter.permalink; return frontmatter; }, }, }, }); ``` 如果想清空其他属性,请自行修改 `transform` 函数的 `delete frontmatter.{配置}` 内容。 ::: warning 一旦删除指定的属性后,则需要去掉 `transform` 的删除逻辑,否则每次启动项目都会尝试删除该属性,可能会对后续使用该属性造成影响。 ::: --- --- url: /10.配置/10.Frontmatter 配置.md --- # Frontmatter 配置 `frontmatter` 支持基于页面的配置。在每个 Markdown 文件中,可以使用 `frontmatter` 配置来覆盖 [主题配置](/reference/config) 中的大部分选项。 ## 首页配置 ### description Teek 提供了 `description` 选项,用于在首页 Banner 展示一些描述信息,您可以通过 `tk.description` 或者 `tk.banner.description` 来配置首页的 `description`。 ::: tip `description` 获取优先级:`tk.banner.description` > `banner.description` > `tk.description` >。 ::: ```yaml --- layout: home tk: description: - 故事由我书写,旅程由你见证,传奇由她聆听 —— 来自 Young Kbt - 积跬步以至千里,致敬每个爱学习的你 —— 来自 Evan Xu - 这一生波澜壮阔或是不惊都没问题 —— 来自 Weibw --- ``` ### features Teek 提供了 `features` 选项,用于在首页展示一些功能介绍。 请通过 `frontmatter.tk.features` 配置 `features`,这样可以避免与 VitePress 的 `features` 冲突。 如果您是博客风格,你也可以通过 `frontmatter.tk.banner.features` 或 `frontmatter.banner.features` 配置 `features`。 ::: tip `features` 获取优先级 * 文档风格::`frontmatter.tk.features` > `teekConfig.features` * 博客风格:`frontmatter.tk.banner.features` > `frontmatter.banner.features` > `teekConfig.banner.features` ::: * 文档风格的 `features` 配置内容请看 [Doc Feature](/reference/config/global-config#features)。 * 博客风格风格的 `features` 配置内容请看 [Banner Feature](/reference/banner-config.html#banner)。 ::: code-group ```yaml [文档风格] tk: teekHome: false features: - title: 快速开发 details: 提供了完整版参考代码和精简版开发代码 image: /feature/ui.svg highlights: - title: 从零安装:运行 pnpm add vitepress-theme-teek vitepress 以从 NPM 下载 Teek 主题。 - title: 现有模板:运行 git clone https://github.com/Kele-Bingtang/vitepress-theme-teek-docs-template.git 以下载当前文档模板。 - title: 拥有丰富的 Features,并持续更新 details: 满足大部分开发场景。 image: /feature/features.svg features: - title: 最新流行稳定技术栈 icon: icon-github details: 基于 Vue3.2、TypeScript、Vite4、Pinia、Element-Plus 等最新技术栈开发 link: /guide/intro - title: 简单上手 & 学习 icon: details: 项目结构清晰,代码简单、易读。 - title: 规范工程化工作流 icon: /teek-logo-mini.svg details: 配置 Eslint、Prettier、Husky、Commitlint、Lint-staged 规范前端工程代码规范。 - title: 完善的打包优化方案 icon: icon-github details: 内置规范的打包目录,提供打包压缩功能,减少打包体积。 - title: 丰富的组件 icon: /teek-logo-mini.svg details: 提供丰富的通用组件、业务组件。 link: /ecosystem/components - title: 常用 Hook 函数 icon: icon-gitee details: 提供丰富的组件、常用 Hooks 封装,实现复用思想,减少重复开发,提高效率。 - title: 个性化主题配置 icon: icon-xiangce details: 提供主题颜色配置,暗黑、灰色、色弱等模式切换。 link: /guide/theme-enhance - title: 多种布局配置 icon: /teek-logo-mini.svg details: 提供多种布局、标签栏切换,布局显隐,满足大部分场景。 - title: 项目权限管控 icon: /teek-logo-mini.svg details: 采用 RBAC 权限管控,提供菜单、路由及按钮粗细粒度权限管理方案 - title: 国际化 icon: /teek-logo-mini.svg details: 内置常用国际化转换函数,支持自定义国际化切换, - title: IFrame 嵌入 icon: /teek-logo-mini.svg details: 提供 IFrame 嵌入、缓存功能,支持门户 Portal 布局。 - title: 自定义指令 icon: /teek-logo-mini.svg details: 内置多种 Vue 自定义指令,提供傻瓜式指令一键注册功能。 - title: Axios 封装 icon: /teek-logo-mini.svg details: 基于 Axios 封装常用请求模块,内置业务拦截器、异常拦截器。 - title: 多种图标类型 icon: /teek-logo-mini.svg details: 支持 IconFont、SVG、Iconify 等多种图标类型渲染。 link: /guide/icon-use - title: 布局 details: 多种布局、标签栏切换,布局组件显隐 image: /feature/layout.svg highlights: - title: 六大布局 icon: /teek-logo-mini.svg details: 内置纵向、经典、横向、分栏、混合、子系统六大布局切换 - title: 深色模式 icon: /teek-logo-mini.svg details: 可以自由切换浅色模式与深色模式 - title: 主题色切换 icon: /teek-logo-mini.svg details: 支持自定义主题色并允许用户在预设的主题颜色之间切换 - title: 布局组件 icon: /teek-logo-mini.svg details: 支持图标、面包屑、导航栏等组件显隐,内置缓存功能,记住用户的布局配置 ``` ```yaml [博客风格] --- layout: home tk: features: - title: 指南 details: Hd Security 使用指南说明 link: /01.指南/ images: /img/web.png - title: 设计 description: Hd Security 设计思路说明 link: /design/ images: /img/ui.png - title: API description: Hd Security 所有的 API 介绍 link: /07.API/01.API - 登录/ images: /img/other.png --- ``` ::: ### 主题配置 在首页 `index.md` 的 `frontmatter`,可以覆盖 `config` 主题配置的首页相关选项: * `banner` 横幅 * `topArticle` 精选文章 * `category` 分类 * `tag` 标签 * `friendLink` 友情链接 * `docAnalysis` 站点分析 * `post` 文章列表 * `article` 文章信息(作者、创建时间、分类、标签等) * `page` 分页 * ... 在首页 `index.md` 的 `frontmatter` 中配置时,建议以 `tk` 开头,然后是主题配置的选项,举个示例: ```yaml --- tk: banner: enabled: true bgStyle: fullImg imgSrc: - /img/bg1.jpg - /img/bg2.jpg category: enabled: true limit: 7 article: showIcon: false page: pageSize: 20 --- ``` 这些配置将会覆盖 `config` 主题配置中的对应选项。 ::: tip 不以 `tk` 开头也是可以的,Teek 支持的 frontmatter 既可以是 `tk.xx.xx`,也可以是 `xx.xx`,其中 `tk.xx.xx` 优先级更高。 ::: ## 文章页配置 在文章页的 `frontmatter`,可以覆盖 `config` 主题配置的文章页相关选项: * `author` 作者信息 * `article` 文章信息(作者、创建时间、分类、标签等) * `breadcrumb` 面包屑 * `articleShare` 文章分享 * `appreciation` 赞赏 * ... 在文章页的 `frontmatter` 中配置时,直接填写 `config` 主题配置的对应选项,举个示例: ```yaml --- author: name: TianKe link: https://github.com/Kele-Bingtang/vitepress-theme-teek article: showCategory: true breadcrumb: separator: - --- ``` ## 文章配置 除了支持覆盖主题配置的选项,Teek 还提供了以下额外的选项: ```yaml --- title: 标题 date: 2025-03-07 01:16:28 permalink: /pages/b1ad26 categories: - 分类 1 - 分类 2 tags: - 标签 1 titleTag: 原创 top: true sticky: 1 sidebar: true article: true comment: true description: 文章摘要 coverImg: /img/web.png docAnalysis: true inCatalogue: true autoTitle: true articleUpdate: true inHomePost: true sidebarSort: 9999 sidebarPrefix: "侧边栏前缀" sidebarSuffix: "侧边栏后缀" articleBanner: true coverBgColor: "#395AE3" --- ``` ### title * 类型:`string` 页面标题,将作为一级标题显示在页面上。 支持填写 HTML 标签 : ::: code-group ```yaml [基础 HTML] --- title: frontmatter 配置 原创 --- ``` ```yaml [Badge 组件] --- title: frontmatter 配置 --- ``` ```yaml [TkTitleTag 组件] --- title: frontmatter 配置 --- ``` ```yaml [TkIcon 图标] --- title: frontmatter 配置 --- ``` ::: 除此之外,`frontmatter.title` 支持所有的基础 HTML 以及已经全局注册的 Vue 组件。 ::: tip 如何注册全局 Vue 组件 在 `.vitepress/theme/index.ts` 中的 `enhanceApp` 函数中进行,通过 `app.component("your componentName", your component)` 方法进行注册。 ::: ### date * 类型:`string` 页面创建时间,将作为创建时间显示在首页的文章列表、文章页顶部。 ### permalink * 类型:`string` 页面永久链接,将作为页面访问的 URL 路径,该配置项由 `vitepress-plugin-permalink` 提供。 ### categories * 类型:`string[]` 分类,将显示在首页的文章列表、分类卡片、文章页顶部,并在分类页渲染所有分类的文章。 ### tags * 类型:`string[]` 标签,将显示在首页的文章列表、标签卡片、文章页顶部,并在标签页渲染所有标签的文章。 ### titleTag 用于给标题添加 `原创`、`转载`、`优质`、`推荐` 等自定义标记。 添加了标题标记的文章,在文章列表、文章页、归档页、目录页的文章标题都会显示此标记。 除此之外,也可以直接在 `frontmatter.title` 前后通过 `` 组件的方式添加标题标记。 ::: code-group ```yaml [标题后] --- title: frontmatter 配置 --- ``` ```yaml [标题前] --- title: frontmatter 配置 --- ``` ::: ### top * 类型:`boolean` * 默认值:`false` 标记为精选文章。如果为 `true`,则在首页的精选文章卡片中显示,如果多个文章都设置了 `top: true`,则按照 `date` 进行排序(最新时间在上面)。 ### sticky * 类型:`number` 文章置顶,设置了此项将在首页文章列表中处于置顶位置,如果同时设置了 `top: true`,则在精选文章卡片的序号添加高亮背景色,背景色请看 [主题配置 - tagColor](/config/theme#tagColor)。 ### sidebar * 类型:`boolean` * 默认值:`true` 侧边栏,`true` 表示显示侧边栏。设置为 `false` 表示不显示侧边栏。 ### article * 类型:`boolean` * 默认值:`true` 非文章页的标记,非文章页如目录页、关于、友情链接等自定义页面,需要设置此项。设置之后这个页面将被认定为非文章页,不显示面包屑和文章信息(作者、时间、分类、标签等),不显示在如下模块中: * 首页的文章列表 * 归档页 * 文章最近更新栏 ### comment * 类型:`boolean` * 默认值:`true` 评论功能,`true` 表示显示评论区。设置为 `false` 表示不显示评论区。 ### description * 类型:`string` * 默认值:null 文章摘要,将显示在首页的文章列表。 ### coverImg * 类型:`string` * 默认值:null 封面图片,将显示在首页的文章列表。 ### inCatalogue * 类型:`boolean` * 默认值:`true` 目录页,`true` 表示允许 Markdown 文档纳入目录里。设置为 `false` 表示不允许,该配置项由 `vitepress-plugin-catalogue` 插件提供。 ### docAnalysis * 类型:`boolean` * 默认值:`true` 站点分析,`true` 表示允许站点信息功能对 Markdown 文档进行数据分析和统计。设置为 `false` 表示不允许,该配置项由 `vitepress-plugin-doc-analysis` 插件提供。 ### autoTitle * 类型:`boolean` * 默认值:`true` 如果 Markdown 不设置一级标题,在访问页面的时候自动添加一级标题。设置为 `false` 表示不允许自动添加一级标题,该配置项由 `vitepress-plugin-md-h1` 插件提供。 一级标题获取优先级:`frontmatter.title` > 文件名 ### articleUpdate * 类型:`boolean` * 默认值:`true` 是否在文章底部显示最近更新栏。 ### inHomePost * 类型:`boolean` * 默认值:`true` Markdown 文档是否在首页的文章列表中显示。 ### sidebarSort * 类型:`number` * 默认值:`9999` 侧边栏排序,值越小越靠前,设置此项将覆盖文件名序号进行排序,由 `vitepress-plugin-sidebar-resolve` 插件提供。 ### sidebarPrefix * 类型:`string` * 默认值:`""` 侧边栏标题前缀,可以添加 HTML 如 iconfont 图标,由 `vitepress-plugin-sidebar-resolve` 插件提供。 ### sidebarSuffix * 类型:`string` * 默认值:`""` 侧边栏标题后缀,可以添加 HTML 如 iconfont 图标,由 `vitepress-plugin-sidebar-resolve` 插件提供。 ### articleBanner * 类型:`boolean` * 默认值:`true` 是否显示文章页的 Banner 栏,仅当没有侧边栏的文章页生效。 ### coverBgColor * 类型:`string` * 默认值:`""` 文章页 Banner 的背景色,仅当 `articleBanner` 为 true 时生效。 ## 功能页配置 上述的 `frontmatter` 配置为通用配置,适用于任何 Markdown 文档。 除此之外,还有一些针对功能页的 `frontmatter` 局部配置,详细请看 [目录页配置](/reference/catalogue-page) 和 [功能页配置](/reference/function-page)。 --- --- url: /30.生态/10.Helper 工具.md --- # Helper 工具 Teek 提供了工具类,提高开发效率。 ## 时间 ### getNowDate 获取当前时间,返回格式为 `yyyy-MM-dd HH:mm:ss`。 ```ts import { getNowDate } from "vitepress-theme-teek"; getNowDate(); // 2025-01-13 00:00:00 getNowDate("yyyy-MM-dd"); // 2025-01-13 ``` ### formatDate 格式化时间 ```ts import { formatDate } from "vitepress-theme-teek"; formatDate(new Date()); // 2025-01-13 00:00:00 formatDate("2025-01-13 00:00:00", "yyyy-MM-dd"); // 2025-01-13 ``` 类型: ```ts const formatDate: (date: Date | string | number, format = "yyyy-MM-dd hh:mm:ss") => string; ``` ### formatDiffDate 计算相差时间差,返回多少年(月/天/时/分/秒)前 ```ts import { formatDate } from "vitepress-theme-teek"; formatDiffDate("2025-01-13 00:00:00", "2025-01-14 01:00:00"); // 1 天前 formatDiffDate("2025-01-13 00:00:00"); // 2月前(与当前日期计算) ``` 类型: ```ts const formatDiffDate: (startDate: Date | string | number, endDate?: Date | string | number) => string; ``` ### formatDiffDateToDay 计算时间相差到天 ```ts import { formatDiffDateToDay } from "vitepress-theme-teek"; formatDiffDateToDay("2021-10-19"); // 1258 天 ``` 类型: ```ts const formatDiffDateToDay: (startDate: Date | string | number, endDate?: Date | string | number) => number; ``` ## 校验 Teek 提供了一系列用于校验数据类型的工具函数,帮助开发者快速验证变量的类型或状态。 本内容仅列出常用的校验工具函数,更多请看 [校验文件](https://github.com/Kele-Bingtang/vitepress-theme-teek/tree/master/packages/helper/is.ts)。 ### isExternal 校验是否为合法的 URL 前缀(如 `http://`、`https://`、`mailto:`、`tel:`)。 ```ts import { isExternal } from "vitepress-theme-teek"; isExternal("https://example.com"); // true isExternal("mailto:test@example.com"); // true isExternal("/path/to/file"); // false ``` 类型: ```ts const isExternal: (path: string) => boolean; ``` ### isValidURL 校验是否为有效的 URL。 ```ts import { isValidURL } from "vitepress-theme-teek"; isValidURL("https://example.com"); // true isValidURL("ftp://example.com"); // true isValidURL("invalid-url"); // false ``` 类型: ```ts const isValidURL: (url: string) => boolean; ``` ### isFunction 判断是否为函数。 ```ts import { isFunction } from "vitepress-theme-teek"; isFunction(() => {}); // true isFunction({}); // false ``` 类型: ```ts const isFunction: (val: unknown) => val is T; ``` ### isObject 判断是否为对象。 ```ts import { isObject } from "vitepress-theme-teek"; isObject({}); // true isObject([]); // false isObject(null); // false ``` 类型: ```ts const isObject: (val: any) => val is Record; ``` ### isDate 判断是否为日期对象。 ```ts import { isDate } from "vitepress-theme-teek"; isDate(new Date()); // true isDate("2025-01-01"); // false ``` 类型: ```ts const isDate: (val: unknown) => val is Date; ``` ### isNumber 判断是否为有效的数字(包含正负整数、0 以及正负浮点数)。 ```ts import { isNumber } from "vitepress-theme-teek"; isNumber("123"); // true isNumber("-123.45"); // true isNumber("abc"); // false ``` 类型: ```ts const isNumber: (val: unknown) => val is number; ``` ### isAsyncFunction 判断是否为异步函数。 ```ts import { isAsyncFunction } from "vitepress-theme-teek"; isAsyncFunction(async () => {}); // true isAsyncFunction(() => {}); // false ``` 类型: ```ts const isAsyncFunction: (val: unknown) => val is Promise; ``` ### isPromise 判断是否为 Promise 对象。 ```ts import { isPromise } from "vitepress-theme-teek"; isPromise(Promise.resolve()); // true isPromise({ then: () => {} }); // false ``` 类型: ```ts const isPromise: (val: unknown) => val is Promise; ``` ### isString 判断是否为字符串。 ```ts import { isString } from "vitepress-theme-teek"; isString("hello"); // true isString(123); // false ``` 类型: ```ts const isString: (val: unknown) => val is string; ``` ### isStringNumber 判断是否为字符串数字。 ```ts import { isStringNumber } from "vitepress-theme-teek"; isStringNumber("hello"); // false isString("123"); // true ``` 类型: ```ts const isStringNumber: (val: string) => boolean; ``` ### isBoolean 判断是否为布尔值。 ```ts import { isBoolean } from "vitepress-theme-teek"; isBoolean(true); // true isBoolean(1); // false ``` 类型: ```ts const isBoolean: (val: unknown) => val is boolean; ``` ### isArray 判断是否为数组。 ```ts import { isArray } from "vitepress-theme-teek"; isArray([]); // true isArray({}); // false ``` 类型: ```ts const isArray: (arg: any) => boolean; ``` ### isClient 判断是否在客户端环境。 ```ts import { isClient } from "vitepress-theme-teek"; isClient(); // true (在浏览器中) ``` 类型: ```ts const isClient: () => boolean; ``` ### isEmpty 判断是否为空值(包括空字符串、`null`、`undefined`、空数组和空对象)。 ```ts import { isEmpty } from "vitepress-theme-teek"; isEmpty(""); // true isEmpty([]); // true isEmpty({}); // true isEmpty("hello"); // false ``` 类型: ```ts const isEmpty: (val: any, checkFull?: boolean) => boolean; ``` ### isFocusable 确定目标元素是否可聚焦。 ```ts import { isFocusable } from "vitepress-theme-teek"; isFocusable(document.querySelector("input")); // true isFocusable(document.querySelector("span")); // false ``` 类型: ```ts const isFocusable: (element: HTMLElement) => boolean; ``` ## 其他 ### withBase 为路径添加站点根路径前缀。 ```ts import { withBase } from "vitepress-theme-teek"; withBase("/notes", "/foo"); // /notes/foo ``` 类型: ```ts const withBase: (base: string, path: string | undefined) => string | undefined; ``` ### upperFirst 将字符串的第一个字符大写。 ```ts import { upperFirst } from "vitepress-theme-teek"; upperFirst("hello"); // Hello ``` 类型: ```ts const upperFirst: (str: string) => string; ``` ### addUnit 添加像素单位。 ```ts import { addUnit } from "vitepress-theme-teek"; addUnit(16); // 16px addUnit("16"); // 16rem addUnit("16", "rem"); // 16rem ``` 类型: ```ts const addUnit: (str: string | number) => string; ``` ### removeUnit 移出像素单位。 ```ts import { addUnit } from "vitepress-theme-teek"; removeUnit("16px"); // 16 removeUnit("16rem", "rem"); // 16 ``` 类型: ```ts const removeUnit: (str: string | number) => number | undefined; ``` ### get 获取对象的值,支持深层次获取。 ```ts import { get } from "vitepress-theme-teek"; const obj = { author: { name: "Teek", }, }; get(obj, "author.name"); // Teek get(obj, "author.link", "https://vp.teek.top/"); // https://vp.teek.top/ ``` 类型: ```ts const get: (object: Record, path: string, defaultValue?: any) => any; ``` --- --- url: /30.生态/04.主题组件/Home 首页.md --- # Home 首页 使用首页组件可以快速搭建一个精美的博客首页。 ## 基础使用 ```ts import { h } from "vue"; import DefaultTheme from "vitepress/theme"; import { TkHome, teekConfigContext } from "vitepress-theme-teek"; import "vitepress-theme-teek/theme-chalk/tk-home-banner-bg-image.css"; import "vitepress-theme-teek/theme-chalk/tk-home-banner-bg-pure.css"; import "vitepress-theme-teek/theme-chalk/tk-home-banner-bg-content.css"; import "vitepress-theme-teek/theme-chalk/tk-home-banner-bg-feature.css"; import "vitepress-theme-teek/theme-chalk/tk-home-banner-bg-waves.css"; import "vitepress-theme-teek/theme-chalk/tk-home-banner.css"; import "vitepress-theme-teek/theme-chalk/tk-home-card.css"; import "vitepress-theme-teek/theme-chalk/tk-home-category-card.css"; import "vitepress-theme-teek/theme-chalk/tk-home-doc-analysis-card.css"; import "vitepress-theme-teek/theme-chalk/tk-home-friend-link-card.css"; import "vitepress-theme-teek/theme-chalk/tk-home-fullscreen-wallpaper.css"; import "vitepress-theme-teek/theme-chalk/tk-home-my-card.css"; import "vitepress-theme-teek/theme-chalk/tk-home-card-list.css"; import "vitepress-theme-teek/theme-chalk/tk-home-post-item.css"; import "vitepress-theme-teek/theme-chalk/tk-home-post-list.css"; import "vitepress-theme-teek/theme-chalk/tk-home-tag-card.css"; import "vitepress-theme-teek/theme-chalk/tk-home-top-article-card.css"; import "vitepress-theme-teek/theme-chalk/tk-home.css"; provide(teekConfigContext, { // ... 更多配置请看配置系列文章 }); export default { extends: DefaultTheme, Layout: () => h(DefaultTheme.Layout, null, { "home-hero-before": () => h(TkHome), }), }; ``` --- --- url: /30.生态/03.公共组件/Icon 图标.md --- # Icon 图标 ## 基础用法 Icon 支持如下类型: * svg * unicode * iconfont * symbol * img * component * iconifyOffline * iconifyOnline 提供传入 `iconType` 来设置图标类型。 ::: demo icon/basic ::: ## 简写使用 Icon 支持特定的格式来自动识别图标类型,无需传入 `iconType`。 1. icon 为 `img-` 或 `IMG-` 开头,或者以 `.png`、`.jpg` 等图片后缀结尾,`iconType` 默认为 `img` 2. icon 为 `` | — | IconType 类型为 `svg` / `unicode` / `iconfont` / `symbol` / `img` / `component` / `iconifyOffline` / `iconifyOnline`。 ### 插槽 | 插槽名 | 说明 | | :------ | :------------- | | default | 自定义图标内容 | --- --- url: /30.生态/03.公共组件/ImageViewer 图片预览.md --- # ImageViewer 图片预览 ## 图片预览 通过 `createImageViewer` 函数来打开图片预览 ::: demo imageViewer/basic ::: ## API ### 配置项 | 事件名 | 说明 | 类型 | 默认值 | | :----------------- | :--------------------------------------------------------------------------------------- | :------------------ | :----- | | urlList | 用于预览的图片链接列表 | `string[]` | \[] | | zIndex | 预览时遮罩层的 z-index | `number` / `string` | — | | initialIndex | 初始预览图像索引,小于 `url-list` 的长度 | `number` | 0 | | infinite | 是否可以无限循环预览 | `boolean` | true | | hideOnClickModal | 是否可以通过点击遮罩层关闭预览 | `boolean` | false | | teleported | image 自身是否插入至 body 元素上。 嵌套的父元素属性会发生修改时应该将此属性设置为 `true` | `boolean` | false | | zoomRate | 图像查看器缩放事件的缩放速率。 | `number` | 1.2 | | minScale | 图像查看器缩放事件的最小缩放比例 | `number` | 0.2 | | maxScale | 图像查看器缩放事件的最大缩放比例 | `number` | 7 | | closeOnPressEscape | 是否可以通过按下 ESC 关闭 | `boolean` | true | | showProgress | 是否显示预览图片的进度条内容 | `boolean` | false | ### 方法 | 事件名 | 说明 | 类型 | | :----- | :------------------------------------------------------------------- | :------------------------ | | close | 当点击 X 按钮或者在 `hide-on-click-modal` 为 true 时点击遮罩层时触发 | `() => void` | | switch | 切换图像时触发。 | `(index: number) => void` | | rotate | 旋转图像时触发。 | `(deg: number) => void` | 这样使用: ```vue ``` --- --- url: /30.生态/03.公共组件/InputSlide 滑块.md --- # InputSlide 滑块 ## 基础用法 ::: demo inputSlide/basic ::: ## API ### 配置项 | 名称 | 说明 | 类型 | 默认值 | | -------- | ----------------- | ------------------------- | ------ | | v-model | 绑定值 | `number` | 0 | | min | 最小值 | `number` | 0 | | max | 最大值 | `number` | 100 | | step | 步长 | `number` | 1 | | disabled | 是否禁用 | `boolean` | false | | format | 格式化显示的内容 | `(val: number) => string` | — | | name | input 标签的 name | `string` | Slider | --- --- url: /01.指南/10.使用/05.Markdown 拓展.md --- # Markdown 拓展 VitePress 使用 `markdown-it` 来对 Markdown 进行解析和渲染,最终转为 Vue 组件。 `markdown-it` 是一款功能强大的 Markdown 解析器,支持丰富的 Markdown 语法,能够轻松将 Markdown 文本转换为 HTML 格式,并提供了许多语法扩展和插件。如果希望文章页拓展一些新的功能、UI,那么可以利用它拦截并处理 Markdown 生成的 HTML。 阅读 VitePress 的代码可以发现,它利用 `markdown-it` 添加了代码块高亮、代码块行号、Tip 容器等功能,在 VitePress 官网的 [Markdown 拓展](https://vitepress.dev/zh/guide/markdown) 里,已经详细介绍了 VitePress 支持 Markdown 额外拓展的功能。 下面介绍的仅仅是 Teek 实现的 Markdown 拓展。 Teek 也提供了几个 Markdown 插件,分别为: * todo 待办列表 * center 内容居中容器 * right 内容居右容器 * note 容器 * shareCard 分享卡片 * imgCard 图文卡片 * navCard 导航卡片 * demo 容器 * ... `center`、`right`、`note` 容器是一种简单的 Markdown 容器(不改变内容,只给内容加样式),Teek 支持定义类似的容器,具体请看 [自定义容器](/reference/plugin-config#自定义容器)。 `shareCard`、`imgCard`、`navCard` 是一种较为复杂的 Markdown 容器(改变内容和样式),如果你也想定义类似的容器,可以阅读这三个插件的代码,它们的代码逻辑非常相似且简单,只需要会编写 HTML、CSS,就可以实现一个复杂容器。 ## TODO 待办列表 输出: * \[ ] 吃饭 * \[ ] 睡觉 * \[x] 打豆豆 输入: ```markdown - [ ] 吃饭 - [ ] 睡觉 - [x] 打豆豆 ``` 确保 `[ ]` 里有一个空格。 ::: tip 支持所有列表语法,如:`1.`、`-`、`+`、`*` 等。 ::: ## 内容居中容器 输出: ::: center Markdown 拓展 ::: ::: center ## Markdown 拓展 (这是二级标题) ::: 输入: ```markdown ::: center Markdown 拓展 ::: ::: center ## Markdown 拓展 (这是二级标题) ::: ``` ## 内容居右容器 输出: ::: right @Teek ::: ::: tip 摘要 很久之前,我决定踏上的这条路,映照了我与未来的因果。 ::: right 2021-11-13 @Teek ::: 输入: ```markdown ::: right @Teek ::: ::: tip 摘要 很久之前,我决定踏上的这条路,映照了我与未来的因果。 ::: right 2021-11-13 @Teek ::: ``` ## 笔记容器 笔记容器和 VitePress 的 Github `NOTE` 容器样式一样,Teek 将其转为 `:::note` 启用。 输出: ::: note 这是一个笔记 Note 容器。 ::: 输入: ```markdown ::: note 这是一个笔记 Note 容器。 ::: ``` ## shareCard 分享卡片 分享卡片容器,可用于 `友情链接、项目推荐、诗词展示` 等。 输出: ::: shareCard ```yaml - name: George Chan desc: 让我给你讲讲他的传奇故事吧 avatar: https://z3.ax1x.com/2021/09/30/4oKMVI.jpg link: https://cyc0819.top/ bgColor: "#FFB6C1" textColor: "#621529" - name: butcher2000 desc: 即使再小的帆,也能远航 avatar: https://gcore.jsdelivr.net/gh/Kele-Bingtang/static/user/20211029181901.png link: https://blog.csdn.net/weixin_46827107 bgColor: "#CBEAFA" textColor: "#6854A1" - name: Evan's blog desc: 前端的小学生 avatar: https://gcore.jsdelivr.net/gh/xugaoyi/image_store/blog/20200103123203.jpg link: https://xugaoyi.com/ bgColor: "#B9D59C" textColor: "#3B551F" ``` ::: 输入: ````yaml ::: shareCard ```yaml - name: George Chan desc: 让我给你讲讲他的传奇故事吧 avatar: https://z3.ax1x.com/2021/09/30/4oKMVI.jpg link: https://cyc0819.top/ bgColor: "#FFB6C1" textColor: "#621529" - name: butcher2000 desc: 即使再小的帆,也能远航 avatar: https://gcore.jsdelivr.net/gh/Kele-Bingtang/static/user/20211029181901.png link: https://blog.csdn.net/weixin_46827107 bgColor: "#CBEAFA" textColor: "#6854A1" - name: Evan's blog desc: 前端的小学生 avatar: https://gcore.jsdelivr.net/gh/xugaoyi/image_store/blog/20200103123203.jpg link: https://xugaoyi.com/ bgColor: "#B9D59C" textColor: "#3B551F" ``` ::: ```` ### 语法 ::: code-group ````markdown [基础语法] ::: shareCard <每行显示数量 | auto> ```yaml - name: 名称 desc: 描述 avatar: https://xxx.jpg # 头像,可选 link: https://xxx/ # 链接,可选 bgColor: "#CBEAFA" # 背景色,可选,默认 var(--vp-c-gray-1)。颜色值有 # 号时请添加引号 textColor: "#6854A1" # 文本色,可选,默认 var(--vp-c-text-1) ``` :::  ```` ````markdown [进阶语法] ::: shareCard <每行显示数量 | auto> ```yaml config: cardNum: 2 # 每行显示的卡片数量,默认为 auto,可在容器名字后面添加,如 ::: shareCard 3 target: _blank # 跳转方式,默认为 _blank,仅支持 _blank | _self cardGap: 20 # 每行卡片之间的间隔,默认为 20 showCode: false # 是否显示代码块,默认为 false data: - name: 名称 desc: 描述 avatar: https://xxx.jpg # 头像,可选 link: https://xxx/ # 链接,可选 bgColor: "#CBEAFA" # 背景色,可选,默认 var(--vp-c-gray-1)。颜色值有 # 号时请添加引号 textColor: "#6854A1" # 文本色,可选,默认 var(--vp-c-text-1) ``` :::  ```` ```ts [配置项] export declare namespace ShareCard { export interface Config { /** * 每行显示的卡片数量 * * @default 'auto' */ cardNum?: number | "auto"; /** * 跳转方式 * * @default '_blank' */ target?: "_blank" | "_self"; /** * 每行卡片之间的间隔 * * @default 20 */ cardGap?: number; /** * 是否显示代码块 */ showCode?: boolean; } export interface Item { /** * 名称 */ name: string; /** * 描述 */ desc: string; /** * 头像 */ avatar?: string; /** * 跳转链接 */ link?: string; /** * 背景色 * @default var(--vp-c-gray-1) */ bgColor: string; /** * 文字颜色 * @default var(--vp-c-text-1) */ textColor: string; } } ``` ::: * `<每行显示数量 | auto>` * 当为空或为 `auto` 时,自动根据文档宽度进行适配 * 为数字时,表示每行最多显示多少个,选值范围 `1 ~ 4`(自带自适应功能:根据屏幕宽度减少每行显示数量) * 代码块需指定语言为 `yaml` ## imgCard 图文卡片 图文卡片容器,可用于 `项目展示、产品展示` 等。 输出: ::: imgCard ```yaml - img: https://vp.teek.top/blog/bg1.webp link: https://vp.teek.top name: 标题 desc: 描述内容描述内容描述内容描述内容 author: Teek avatar: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/user/avatar1.png - img: https://vp.teek.top/blog/bg2.webp link: https://vp.teek.top name: 标题 desc: 描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容 author: Teek avatar: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/user/avatar1.png - img: https://vp.teek.top/blog/bg2.webp link: https://vp.teek.top name: 标题 desc: 描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容 author: Teek avatar: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/user/avatar1.png - img: https://vp.teek.top/blog/bg3.webp link: https://vp.teek.top name: 标题 desc: 描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容 ``` ::: 输入: ````yaml ::: imgCard ```yaml - img: https://vp.teek.top/blog/bg1.webp link: https://vp.teek.top name: 标题 desc: 描述内容描述内容描述内容描述内容 author: Teek avatar: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/user/avatar1.png - img: https://vp.teek.top/blog/bg2.webp link: https://vp.teek.top name: 标题 desc: 描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容 author: Teek avatar: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/user/avatar1.png - img: https://vp.teek.top/blog/bg2.webp link: https://vp.teek.top name: 标题 desc: 描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容 author: Teek avatar: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/user/avatar1.png - img: https://vp.teek.top/blog/bg3.webp link: https://vp.teek.top name: 标题 desc: 描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容 ``` ::: ```` ### 语法 ::: code-group ````markdown [基础语法] ::: imgCard <每行显示数量 | auto> ```yaml - img: https://abc.jpg # 图片地址 link: https://abc.com # 链接地址 name: 标题 desc: 描述 # 可选 author: 作者名称 # 可选 avatar: https://abc.jpg # 作者头像,可选 ``` :::  ```` ````markdown [进阶语法] ::: imgCard <每行显示数量 | auto> ```yaml config: cardNum: 2 # 每行显示的卡片数量,默认为 auto,可在容器名字后面添加,如 ::: imgCard 3 target: _blank # 跳转方式,默认为 _blank,仅支持 _blank | _self lineClamp: 2 # 显示描述信息的行数,默认为 2 cardGap: 20 # 每行卡片之间的间隔,默认为 20 imgHeight: auto # 图片宽度,默认为 auto。仅图文卡片支持该配置项 objectFit: cover # 设置图片的填充方式,支持 cover | fill | contain | scale-down | none,默认为 cover showCode: false # 是否显示代码块,默认为 false data: - img: https://abc.jpg # 图片地址 link: https://abc.com # 链接地址 name: 标题 desc: 描述 # 可选 author: 作者名称 # 可选 avatar: https://abc.jpg # 作者头像,可选 ``` :::  ```` ```ts [配置项] export declare namespace ImgCard { export interface Config { /** * 每行显示的卡片数量 * * @default 'auto' */ cardNum?: number | "auto"; /** * 跳转方式 * * @default '_blank' */ target?: "_blank" | "_self"; /** * 图片宽度 * * @default 'auto' */ imgHeight?: string; /** * 设置图片的填充方式,为 CSS object-it 属性值 * * @default 'cover' */ objectFit?: "cover" | "fill" | "contain" | "scale-down" | "none"; /** * 显示描述信息的行数 * * @default 2 */ lineClamp?: number; /** * 每行卡片之间的间隔 * * @default 20 */ cardGap?: number; /** * 是否显示代码块 */ showCode?: boolean; } export interface Item { /** * 图片链接 */ img: string; /** * 跳转链接 */ link?: string; /** * 名称 */ name: string; /** * 描述 */ desc?: string; /** * 作者 */ author?: string; /** * 作者头像 */ avatar?: string; } } ``` ::: * `<每行显示数量 | auto>` * 当为空或为 `auto` 时,自动根据文档宽度进行适配 * 为数字时,表示每行最多显示多少个,选值范围 `1 ~ 4`(自带自适应功能:根据屏幕宽度减少每行显示数量) * 代码块需指定语言为 `yaml` ## navCard 导航卡片 导航卡片容器,可以用于制作 `导航站点`。 输出: ::: navCard ```yaml - name: 百度 desc: 百度——全球最大的中文搜索引擎及最大的中文网站,全球领先的人工智能公司 link: http://www.baidu.com/ img: https://www.baidu.com/favicon.ico badge: 搜索引擎 - name: Google desc: 全球最大的搜索引擎公司 link: http://www.google.com/ img: https://ts1.cn.mm.bing.net/th/id/R-C.58c0f536ec073452434270fb559c3f8c?rik=SnOUNtUtPLX6ww&riu=http%3a%2f%2fwww.sz4a.cn%2fPublic%2fUploads%2fimage%2f20230303%2f1677839482835474.png&ehk=J1lqoeszPGEWzDOSZQ3JxzXsklfd0QzgrJu6ZVvESKk%3d&risl=&pid=ImgRaw&r=0 badge: 搜索引擎 badgeType: tip ``` ::: 输入: ````yaml ::: navCard ```yaml - name: 百度 desc: 百度——全球最大的中文搜索引擎及最大的中文网站,全球领先的人工智能公司 link: http://www.baidu.com/ img: https://www.baidu.com/favicon.ico badge: 搜索引擎 - name: Google desc: 全球最大的搜索引擎公司 link: http://www.google.com/ img: https://ts1.cn.mm.bing.net/th/id/R-C.58c0f536ec073452434270fb559c3f8c?rik=SnOUNtUtPLX6ww&riu=http%3a%2f%2fwww.sz4a.cn%2fPublic%2fUploads%2fimage%2f20230303%2f1677839482835474.png&ehk=J1lqoeszPGEWzDOSZQ3JxzXsklfd0QzgrJu6ZVvESKk%3d&risl=&pid=ImgRaw&r=0 badge: 搜索引擎 badgeType: tip ``` ::: ```` ### 语法 ::: code-group ````markdown [基础语法] ::: navCard <每行显示数量 | auto> ```yaml - name: 标题 desc: 描述 link: 链接地址 # 可选 img: 图片地址 # 可选 badge: 徽章内容 # 可选 badgeType: 徽章类型 # 可选 ``` :::  ```` ````markdown [进阶语法] ::: imgCard <每行显示数量 | auto> ```yaml config: cardNum: 2 # 每行显示的卡片数量,默认为 2,可在容器名字后面添加,如 ::: navCard 3 target: _blank # 跳转方式,默认为 _blank,仅支持 _blank | _self lineClamp: 2 # 显示描述信息的行数,默认为 2 cardGap: 20 # 每行卡片之间的间隔,默认为 20 showCode: false # 是否显示代码块,默认为 false data: - name: 标题 desc: 描述 link: 链接地址 # 可选 img: 图片地址 # 可选 badge: 徽章内容 # 可选 badgeType: 徽章类型 # 可选 ``` :::  ```` ```ts [配置项] export declare namespace NavCard { export interface Config { /** * 每行显示的卡片数量 * * @default 'auto' */ cardNum?: number | "auto"; /** * 跳转方式 * * @default '_blank' */ target?: "_blank" | "_self"; /** * 显示描述信息的行数 * * @default 2 */ lineClamp?: number; /** * 每行卡片之间的间隔 * * @default 20 */ cardGap?: number; /** * 是否显示代码块 */ showCode?: boolean; } export interface Item { /** * 名称 */ name: string; /** * 描述 */ desc: string; /** * 图片链接 */ img?: string; /** * 跳转链接 */ link?: string; /** * 右上角徽章 */ badge?: string; /** * 右上角徽章类型 * * @default 'info' */ badgeType?: "info" | "tip" | "warning" | "danger"; } } ``` ::: * `<每行显示数量 | auto>` * 当为空或为 `auto` 时,自动根据文档宽度进行适配 * 为数字时,表示每行最多显示多少个,选值范围 `1 ~ 4`(自带自适应功能:根据屏幕宽度减少每行显示数量) * 代码块需指定语言为 `yaml` ## Demo 容器 Demo 容器用于展示编写的 Vue 组件输出,且支持查看源代码、复制源代码、去 `Github` 编辑、去 `Playground` 编辑功能: ### 基础使用 这是一个简单的 `primary` 按钮 输出: ::: demo demo/button-primary ::: 输入: ```markdown ::: demo demo/button-primary ::: ``` ### 带描述 输出: ::: demo 这是一个简单的 `info` 按钮 demo/button-info ::: 输入: ```markdown ::: demo 这是一个简单的 `info` 按钮 demo/button-info ::: ``` ### 只渲染组件效果 如果希望只渲染组件效果,不提供其他功能,使用 `effect` 关键词。 输出: ::: demo effect demo/button-primary ::: 输入: ```markdown ::: demo effect demo/button-primary ::: ``` ### 只渲染组件效果和描述 如果希望既只渲染组件效果,也带有描述,则 输出: ::: demo effect 这是一个简单的按钮 demo/button-primary ::: 输入: ```markdown ::: demo effect 这是一个简单的按钮 demo/button-primary ::: ``` ### 渲染组件和源码文件区分 有些场景希望页面渲染的效果是一个 Vue 组件,查看源代码并复制是另一个 Vue 组件,此时使用 `yaml` 语法指定组件和源码文件: 输出: ::: demo 此时页面看到的效果 `demo/button-info` 组件,但是展开源代码查看的是 `demo/button-primary` 组件代码 ```yaml effect: demo/button-info file: demo/button-primary ``` ::: 输入: ````markdown ::: demo ```yaml effect: demo/button-info file: demo/button-primary ``` ::: ```` ::: tip * `effect` 的文件要求必须是 `.vue` 文件,写 `demo/button-info` 或者 `demo/button-info.vue` 都可以 * `file` 默认的文件后缀是 `.vue`,如果您的文件后缀不是 `.vue`,请指定文件后缀,如 `demo/button-primary.md` ::: ### 额外说明 Demo 容器默认在项目根目录的 `examples` 目录下寻找组件,如指定 `demo/button-primary` 路径,则目录结构应该如下: ```sh . ├─ .vitepress # 默认基于 vitepress(项目根目录)层级下的 examples 目录扫描 ├─ examples │ ├─ demo │ │ ├─ button-primary.vue ``` ::: warning * Demo 容器暂不支持更改 `examples` 为其他目录 * Demo 容器无法渲染在 `` 生成的文章摘要里 ::: Demo 容器的更多配置请查看 [Demo 容器](/reference/plugin-config#demo)。 ## Video 容器 `Video` 容器可以快速嵌入不同平台的视频: * `bilibili`:Bilibili 视频 * `tencent`:腾讯视频 * `youku`:优酷视频 * `youtube`:YouTube 视频 * `vimeo`:Vimeo 视频 * `xigua`:西瓜视频 * 自定义视频链接 以 `bilibili` 为例,输出: ::: video bilibili BV11e411m7e8 ::: 输入: ```markdown ::: video bilibili BV11e411m7e8 ::: ``` 自定义视频链接,输出: ::: video https://player.bilibili.com/player.html?bvid=BV11e411m7e8\&autoplay=0 ::: 输入: ```markdown ::: video https://player.bilibili.com/player.html?bvid=BV11e411m7e8&autoplay=0 ::: ``` ### 语法 ::: code-group ```markdown [多平台] ::: video <视频平台标识> <视频 ID> :::  ``` ```markdown [自定义] ::: video <自定义视频链接> :::  ``` ::: --- --- url: /30.生态/30.Markdown 插件工具.md --- # Markdown 插件工具 Teek 提供了 Markdown 插件工具,用于快速开发 Markdown 容器。 ## 简单容器 创建简单容器: ::: code-group ```ts [创建简单容器数据并直接使用] import { createContainerThenUse } from "vitepress-theme-teek"; import MarkdownIt from "markdown-it"; // 创建 markdown it 实例 const md = MarkdownIt({ html: true, linkify: true }); const containerInfo = createContainerThenUse(md, { type: "center", useTitle: false, className: `tk-center-container`, }); ``` ```ts [创建简单容器数据并获取] import { createContainerThenGet } from "vitepress-theme-teek"; import MarkdownIt from "markdown-it"; // 创建 markdown it 实例 const md = MarkdownIt({ html: true, linkify: true }); const containerInfo = createContainersThenUse(md, { type: "center", useTitle: false, className: `tk-center-container`, }); md.use(containerInfo); ``` ::: 一次性创建多个简单容器: ::: code-group ```ts [创建多个简单容器数据并直接使用] import { createContainersThenUse } from "vitepress-theme-teek"; const markdownContainer = [ { type: "center", useTitle: false, className: `tk-center-container` }, { type: "right", useTitle: false, className: `tk-right-container` }, { type: "note", useTitle: true, defaultTitle: containerLabel?.noteLabel || "NOTE", className: `custom-block` }, ]; createContainersThenUse(md, markdownContainer); ``` ```ts [创建多个简单容器数据并获取] import { createContainersThenGet } from "vitepress-theme-teek"; const markdownContainer = [ { type: "center", useTitle: false, className: `tk-center-container` }, { type: "right", useTitle: false, className: `tk-right-container` }, { type: "note", useTitle: true, defaultTitle: containerLabel?.noteLabel || "NOTE", className: `custom-block` }, ]; const containerInfo = createContainersThenGet(md, markdownContainer); md.use(...containerInfo); ``` ::: ## 卡片容器 创建卡片容器。 ```ts import { createCardContainer } from "vitepress-theme-teek"; import MarkdownIt from "markdown-it"; interface DemoCardItem { /** * 名称 */ name: string; /** * 描述 */ desc?: string; } interface DemoCardConfig { /** * 卡片数量 */ cardNum: number; } // 创建 markdown it 实例 const md = MarkdownIt({ html: true, linkify: true }); createCardContainer(md, { type: "demoCard", className: `demo-card-container`, htmlRender: (props, info) => renderImgCard(props, info), }); const renderDemoCard = (demoCard: { data: DemoCardItem[]; config?: DemoCardConfig }, info: string) => { const { data = [], config = {} } = demoCard; if (!data.length) return ""; const { cardNum = 2 } = config; return `
${data.map(card => `

${info}

${card.name}

`).join("")}
`; }; ``` 一次性创建多个卡片容器: ```ts import { createCardContainers } from "vitepress-theme-teek"; import MarkdownIt from "markdown-it"; // 创建 markdown it 实例 const md = MarkdownIt({ html: true, linkify: true }); createCardContainers(md, [{}, {}]); ``` --- --- url: /30.生态/03.公共组件/Message 消息提示.md --- # Message 消息提示 更多用法使用请看 ElementPlus 的 [Message 文档](https://element-plus.org/zh-CN/component/message.html)。 ## 基础用法 ::: demo message/basic ::: ## antd 风格 通过传入 `customClass: "antd"` 来启用 antd 风格。 ::: demo message/antd ::: ## API ### 配置项 | 名称 | 说明 | 类型 | 默认值 | | :----------------------- | :---------------------------------------------------------------------- | :--------------------------------------- | :----- | | message | 消息文字 | `string` / `VNode` / `() => VNode` | '' | | type | 消息类型 | `success` / `warning` / `info` / `error` | info | | plain | 是否纯色 | `boolean` | false | | icon | 自定义图标,该属性会覆盖 `type` 的图标。 | `string` / `Component` | — | | dangerouslyUseHTMLString | 是否将 message 属性作为 HTML 片段处理 | `boolean` | false | | customClass | 自定义类名 | `string` | '' | | duration | 显示时间,单位为毫秒。 设为 0 则不会自动关闭 | `number` | 3000 | | showClose | 是否显示关闭按钮 | `boolean` | false | | onClose | 关闭时的回调函数, 参数为被关闭的 message 实例 | `() => void` | — | | offset | Message 距离窗口顶部的偏移量 | `number` | 16 | | appendTo | 设置 message 的根元素,默认为 `document.body` | `string` / `HTMLElement` | — | | grouping | 合并内容相同的消息,不支持 VNode 类型的消息 | `boolean` | false | | repeatNum | 重复次数,类似于 Badge 。当和 `grouping` 属性一起使用时作为初始数量使用 | `number` | 1 | ### 方法 调用 `Message` 会返回当前 Message 的实例。 如果需要手动关闭实例,可以调用它的 `close` 方法。 | 名称 | 描述 | 类型 | | :---- | :----------------- | :----------- | | close | 关闭当前的 Message | `() => void` | --- --- url: /30.生态/04.主题组件/Notice 公告栏.md --- # Notice 公告栏 Notice 公告栏仅实现了基础的交互功能,公告内容需要您自己实现,这里给一个 Demo。 在 `.vitepress/theme/components` 定义一个公告内容组件 `NoticeContent.vue`。 ```vue ``` ## 基础使用 ```ts import { defineComponent, h } from "vue"; import DefaultTheme from "vitepress/theme"; import { TkNotice, teekConfigContext } from "vitepress-theme-teek"; import "vitepress-theme-teek/theme-chalk/tk-notice.css"; import NoticeContent from "../components/NoticeContent.vue"; provide(teekConfigContext, { notice: { // ... 更多配置请看配置系列文章 }, }); export default { extends: DefaultTheme, Layout: () => h("div", null, [ h( TkNotice, {}, { "teek-notice-content": () => h(NoticeContent), } ), h(DefaultTheme.Layout), ]), }; ``` --- --- url: /30.生态/03.公共组件/PageCard 分页卡片.md --- # PageCard 分页卡片 PageCard 组件是一个快速构建卡片的组件,因内置分页功能从而取名 PageCard。Teek 使用该组件构建了首页的右侧卡片区域。 ## 基础用法 ::: demo pageCard/basic ::: ## 标题点击 传入 `titleLink` 或 `titleClick` 来支持标题的点击。 ::: demo pageCard/title ::: ## 分页功能 传入 `page` 来实现分页功能,如果想自动翻页,则传入 `autoPage` 为 true。 ::: demo pageCard/pagination ::: ## API ### 配置项 | 事件名 | 说明 | 类型 | 默认值 | | :--------- | :--------------------------------------------------------------------------- | :----------- | :----- | | title | 标题 | `string` | — | | titleLink | 标题链接,如果是 http/https 等协议带头,则打开新窗口跳转,否则在当前窗口跳转 | `string` | — | | titleClick | 标题点击事件,优先级低于 titleLink | `() => void` | — | | page | 是否开启分页功能 | `boolean` | false | | pageSize | 每页显示数量 | `number` | 4 | | total | 数量 | `number` | 0 | | autoPage | 是否开启自动分页 | `boolean` | false | | pageSpeed | 翻页间隔事件,单位毫秒,仅当 autoPage 为 true 生效 | `number` | 400 | ### 插槽 | 插槽名 | 说明 | | :--------- | :----------------- | | default | 自定义主内容 | | title | 自定义标题内容 | | page | 自定义分页区内容 | | page-left | 自定义分页左侧按钮 | | page-right | 自定义分页右侧按钮 | --- --- url: /30.生态/03.公共组件/Pagination 分页.md --- # Pagination 分页 更多用法请看 ElementPlus 的 [Pagination 文档](https://element-plus.org/zh-CN/component/pagination.html)。 Teek 基于 ElementPlus 的 Pagination 组件去掉了 `layout` 的 `sizes` 选项。 ## 基础用法 ::: demo pagination/basic ::: --- --- url: /30.生态/03.公共组件/Popover 弹出框.md --- # Popover 弹出框 ## 展示位置 Popover 弹出框提供 9 种展示位置。 使用 `content` 属性来设置悬停时显示的信息。 由 `placement` 属性决定 Popover 弹出框的位置。该属性值格式为:\[方向]-\[对齐位置],可供选择的四个方向分别是 `top`、`left`、`right`、`bottom`,可供选择的三种对齐方式分别是 `start`、`end`、`null`,默认的对齐方式为 `null`。 以 `placement="left-end"` 为例,Popover 弹出框会显示在悬停元素的左侧,且提示信息的底部与悬停元素的底部对齐。 ::: demo popover/basic ::: ## API ### 属性 | 属性名 | 说明 | 类型 | 默认值 | | :----------- | :------------------------------------------------------------------------------------------------------------------------------------------ | :------------------------------------------ | :----- | | placement | 出现位置 | `click` / `focus` / `hover` / `contextmenu` | bottom | | trigger | 触发方式 | `click` / `focus` / `hover` / `contextmenu` | hover | | content | 显示的内容,也可以通过写入默认 `slot` 修改显示内容 | `string` | '' | | width | 宽度,如果不指定,则会根据内容自动计算 | `string` / `number` | — | | height | 高度,如果不指定,则会根据内容自动计算 | `string` / `number` | — | | disabled | Popover 是否可用 | `boolean` | false | | v-model | Popover 是否显示 | `boolean` | false | | offset | 浮层偏移量,等于 `x-offset` 和 `y-offset` | `number` | 0 | | x-offset | 水平方向浮层偏移量 | `number` | 0 | | y-offset | 垂直方向浮层偏移量 | `number` | 0 | | transition | 定义渐变动画,默认是 el-fade-in-linear | `string` | — | | show-arrow | 是否显示 Tooltip 箭头, 欲了解更多信息,请参考 [ElPopper](https://github.com/element-plus/element-plus/tree/dev/packages/components/popper) | `boolean` | true | | popper-class | 为 popper 添加类名 | `string` | — | | popper-style | 为 popper 自定义样式 | `string` / `object` | — | | trigger-el | 代表 `reference` 插槽的参照元素 | `HTMLElement` | — | | beforePopup | 弹框弹出前的回调,支持返回新的 `top`、`right`、`bottom`、`left` | `PopoverTransformOptions` | — | ```typescript interface PopoverTransformOptions { /** * 弹框的 top 位置 */ top: NumStr; /** * 弹框的 right 位置 */ right: NumStr; /** * 弹框的 bottom 位置 */ bottom: NumStr; /** * 弹框的 left 位置 */ left: NumStr; /** * 触发弹框的 DOM 元素,如果传入 virtualEl 则是 virtualEl 元素 */ triggerElement: HTMLDivElement; /** * 弹框的 DOM 元素 */ popoverElement: HTMLDivElement; } ``` ### 插槽 | 插槽名 | 说明 | | :-------- | :---------------------------- | | default | Popover 内嵌 HTML 文本 | | reference | 触发 Popover 显示的 HTML 元素 | 事件 | 事件 | 说明 | | ----- | ----------------------- | | focus | 显示时触发 | | blur | 隐藏时触发 | | close | `Escape` 按键触发时触发 | --- --- url: /30.生态/04.主题组件/RightBottomButton 右下角按钮组.md --- # RightBottomButton 右下角按钮组 右下角按钮组组件提供返回顶部、跳转到评论区功能。 ## 基础使用 ```ts import { h } from "vue"; import DefaultTheme from "vitepress/theme"; import { TkRightBottomButton } from "vitepress-theme-teek"; export default { extends: DefaultTheme, Layout: () => h("div", null, [h(TkRightBottomButton), h(DefaultTheme.Layout)]), }; ``` --- --- url: /30.生态/04.主题组件/RouteLoading 路由加载.md --- # RouteLoading 路由加载 页面加载 Loading 组件,在切换路由前显示,在切换路由后消失。 ## 基础使用 ```ts import { h } from "vue"; import DefaultTheme from "vitepress/theme"; import { TkRouteLoading, teekConfigContext } from "vitepress-theme-teek"; import "vitepress-theme-teek/theme-chalk/tk-article-update.css"; provide(teekConfigContext, { loading: "Teek 正在加载中...", // 指定加载 Loading 动画的文案 }); export default { extends: DefaultTheme, Layout: () => h("div", null, [h(TkRouteLoading), h(DefaultTheme.Layout)]), }; ``` --- --- url: /30.生态/03.公共组件/Segmented 分段控制器.md --- # Segmented 分段控制器 ## 基础用法 ::: demo segmented/basic ::: ## 图标使用 ::: demo segmented/icon ::: ## API ### 配置项 | 名称 | 说明 | 类型 | 默认值 | | -------- | ------------ | ------------------------------------------ | ------ | | v-model | 选中项绑定值 | `string` / `number` / `object` / `boolean` | — | | options | 选项的数据 | `SegmentedOption[]` | \[] | | disabled | 是否禁用 | `boolean` | false | ### SegmentedOption 配置项 | 名称 | 说明 | 类型 | 默认值 | | ----- | --------------------------- | ----------------------------------------------- | ------ | | value | 选择的值 | `string` / `Object` / `Comment` / `IconifyIcon` | — | | label | 展示名称 | `string` | — | | icon | 展示图标,和 `label` 二选一 | `string` | — | | title | 鼠标悬停的 Tip | `string` | — | | name | input 标签的 name | `string` | — | --- --- url: /30.生态/04.主题组件/ThemeEnhance 主题增强.md --- # ThemeEnhance 主题增强 使用文章分析组件,可以获取文章的创建时间、字数、阅读时间、访问量等信息。 ## 基础使用 ```ts import { h } from "vue"; import DefaultTheme from "vitepress/theme"; import { TkThemeEnhance, teekConfigContext } from "vitepress-theme-teek"; provide(teekConfigContext, { themeEnhance: { // ... 更多配置请看配置系列文章 }, }); export default { extends: DefaultTheme, Layout: () => h(DefaultTheme.Layout, null, { "nav-bar-content-after": () => h(TkThemeEnhance), }), }; ``` --- --- url: /30.生态/03.公共组件/TitleTag 标题标签.md --- # TitleTag 标题标签 这是一个可以放在标题旁边的一个内联组件。 ## 基础用法 ::: demo titleTag/basic ::: ## API ### 属性 | 属性名 | 说明 | 类型 | 默认值 | | :------- | :--- | :------------------------------------- | :------ | | text | 文本 | `string` | — | | type | 类型 | `Type` | — | | position | 位置 | `left` / `right` | '' | | size | 大小 | `large` / `default` / `small` / `mini` | default | Type 类型为: * `vp-primary` * `vp-info` * `vp-success` * `vp-warning` * `vp-danger` * `vp-important` * `ep-primary` * `ep-info` * `ep-success` * `ep-warning` * `ep-danger` `position` 配置项告诉组件位于文本的哪个位置,当为 `left` 时,添加 `margin-right: 4px;` 样式,当为 `right` 时,添加 `margin-left: 4px;` 样式。 ### 插槽 | 插槽名 | 说明 | | :------ | :--------------------------- | | default | 文本,覆盖 props 传来的 text | --- --- url: /30.生态/03.公共组件/TransitionCollapse 折叠动画.md --- # TransitionCollapse 折叠动画 使用 `TransitionCollapse` 组件的动画效果控制内容的展示与隐藏。 ## 基础用法 ::: demo transitionCollapse/basic ::: --- --- url: /@pages/loginPage.md --- --- --- url: /@pages/riskLinkPage.md --- --- --- url: /examples/articlePage/aside.md --- --- --- url: /examples/articlePage/doc.md --- --- --- url: /30.生态/03.公共组件/VerifyCode 验证码.md --- # VerifyCode 验证码 ## 基础用法 ::: demo verifyCode/basic ::: ## 配置项 ### 属性 | 属性名 | 说明 | 类型 | 默认值 | | :------ | :------- | :------- | :----- | | v-model | 二维码值 | `string` | — | --- --- url: /01.指南/10.使用/30.Vite 插件.md --- # Vite 插件 VitePress 是基于 Vite 进行搭建,因此可以编写 Vite 插件来辅助完成一些在无法在浏览器环境完成的动作,比如在 VitePress 启动后,扫描文档目录下的 Markdown 文件,提取 `frontmatter` 的信息进行分析,或在渲染 Markdown 内容前,对其进行加工。 得益于 Vite 环境,Teek 内置了一些 Vite 插件来执行在 Node 环境才能完成的事情,这些插件分别为: * [vitepress-plugin-permalink](https://github.com/Kele-Bingtang/vitepress-theme-teek/blob/master/plugins/vitepress-plugin-permalink/README.md) * [vitepress-plugin-sidebar-resolve](https://github.com/Kele-Bingtang/vitepress-theme-teek/blob/master/plugins/vitepress-plugin-sidebar-resolve/README.md) * [vitepress-plugin-md-h1](https://github.com/Kele-Bingtang/vitepress-theme-teek/blob/master/plugins/vitepress-plugin-md-h1/README.md) * [vitepress-plugin-catalogue](https://github.com/Kele-Bingtang/vitepress-theme-teek/blob/master/plugins/vitepress-plugin-catalogue/README.md) * [vitepress-plugin-doc-analysis](https://github.com/Kele-Bingtang/vitepress-theme-teek/blob/master/plugins/vitepress-plugin-doc-analysis/README.md) * [vitepress-plugin-file-content-loader](https://github.com/Kele-Bingtang/vitepress-theme-teek/blob/master/plugins/vitepress-plugin-file-content-loader/README.md) * [vitepress-plugin-auto-frontmatter](https://github.com/Kele-Bingtang/vitepress-theme-teek/blob/master/plugins/vitepress-plugin-auto-frontmatter/README.md) 这些插件已经上传至 NPM 仓库,具体的使用说明可以前往 NPM 查看使用说明,或者访问 [Github 仓库](https://github.com/Kele-Bingtang/vitepress-theme-teek/tree/master/plugins),每个插件下都有 `README.md` 文档介绍。 也可以在 Teek 的 [配置项](/config/theme#viteplugins) 中查看这些插件。 ## vitepress-plugin-permalink Teek 使用 `vitepress-plugin-permalink` 来实现永久链接功能。 如果想要禁用该插件,进行如下配置: ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { permalink: false, }, }); ``` Teek 默认扫描文档根目录下(`.vitepress` 层级开始)的所有 Markdown 文件,如果希望忽略某些目录,可进行如下配置: ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { permalinkOption: { ignoreList: ["目录名"], // 支持正则表达式 }, }, }); ``` 当希望只扫描指定的目录,可进行如下配置: ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { permalinkOption: { path: "guide", // 基于 .vitepress 目录层级添加,开头不需要有 / }, }, }); ``` ### 国际化 `vitepress-plugin-permalink` 支持国际化功能,在生成 `permalink` 时,默认会给不同语言文档的 `permalink` 添加语言前缀。 假如存在一个 Markdown 文档 `guide.md`,`frontmatter` 内容如下: ```yaml --- title: guide permalink: /guide --- ``` 国际化目录结构如下; ``` docs/ ├─ es/ │ ├─ guide.md ├─ guide.md ``` 那么在生成 `permalink` 时,`es` 语言下的 `guide.md` 的 `permalink` 为 `/es/guide`。 ### 配置项 `permalinkOption` 的详细配置项请看 [Permalink 配置项](https://github.com/Kele-Bingtang/vitepress-theme-teek/blob/master/plugins/vitepress-plugin-permalink/src/types.ts)。 ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { permalinkOption: { /** 配置项 */ }, }, }); ``` ## vitepress-plugin-sidebar-resolve Teek 使用 `vitepress-plugin-sidebar-resolve` 来实现自动生成侧边栏功能。 在 [结构化目录 - 特殊目录](/guide/directory-structure#特殊目录) 和 [结构化目录 - 文档风](/guide/directory-structure#文档风) 中已经介绍了该插件部分使用方式以及注意事项,如果想要禁用该插件,进行如下配置: ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { sidebar: false, }, }); ``` ### 国际化 在国际化的环境下,当把 root 语言(默认语言)的 Markdown 文件放到某个路径下时,`vitepress-plugin-sidebar-resolve` 无法感知到,因此请使用 `localeRootDir` 配置项告诉它,在 [国际化特殊场景](/guide/i18n#给-root-语言添加目录) 有说明。 ### 配置项 `sidebarOption` 的详细配置项请看 [SideBar 配置项](https://github.com/Kele-Bingtang/vitepress-theme-teek/blob/master/plugins/vitepress-plugin-sidebar-resolve/src/types.ts)。 ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { sidebarOption: {}, /** 配置项 */ }, }); ``` ### 侧边栏初始化格式 配置项 `initItems` 和 `initItemsText` 会影响侧边栏的生成格式,举个例子说明: 假设根目录下有目录名为 `guide`: * 当 `initItems` 为 true,则最终结果为 `sidebar: { "/guide": { items: [], collapsed }}` * 当 `initItemsText` 为 true,则最终结果为 `sidebar: { "/guide": { text: "guide", items: [], collapsed }}` * 当 `initItemsText` 为 false,则最终结果为 `sidebar: { "/guide": { items: [] }}` * 当 `initItems` 为 false,则最终结果为 `sidebar: { "/guide": [] }` ### 侧边栏新增图标 如果希望侧边栏标题前新增图标,可以在 `frontmatter.title` 配置: ```yaml --- title: 我是标题 --- ``` 或者单独使用 `frontmatter.sidebarPrefix` 或 `frontmatter.sidebarSuffix` 配置, 插件会将图标并添加到标题前/后 ```yaml --- sidebarPrefix: sidebarSuffix: --- ``` 如果使用的是 `iconfont` 图标,每次使用都要加 ` ` 比较麻烦,因此插件提供了 `prefixTransform` 和 `suffixTransform` 配置项,可以对所有的 `sidebarPrefix` 和 `sidebarSuffix` 进行二次处理,如: ```typescript import { defineConfig } from "vitepress"; import Sidebar from "vitepress-plugin-sidebar-resolve"; export default defineConfig({ vite: { plugins: [ Sidebar({ prefixTransform: prefix => { // 判断是否为 HTML 标签,如果是则直接返回 const htmlTagRegex = /^<([a-zA-Z][a-zA-Z0-9]*)\b[^>]*>/; if (htmlTagRegex.test(prefix)) return prefix; return ``; }, }), ], }, }); ``` 此时在 `frontmatter.sidebarPrefix` 配置如下即可生效: ```yaml --- sidebarPrefix: teek --- ``` 上面演示的是如何在标题前缀添加图标,后缀操作同理。 ## vitepress-plugin-md-h1 Teek 使用 `vitepress-plugin-md-h1` 来给文章页生成一级标题(假如 Markdown 文档没有设置过一级标题)。 一级标题获取顺序:`frontmatter.title` > 文件名 ::: tip 只在页面加载 Markdown 内容时生成一级标题,并不会真正修改 Markdown 文档内容。 ::: 假设一个文档 `install.md` 的 `frontmatter` 内容如下: ```yaml --- title: guide --- ``` 在页面访问该文档时,页面自动生成一级标题 `guide`,当把 `frontmatter.title` 去掉后,页面的一级标题变为 `install`。 如果想要禁用该插件,进行如下配置: ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { mdH1: false, }, }); ``` ### 配置项 `mdH1Option` 的详细配置项请看 [MdH1Option 配置项](https://github.com/Kele-Bingtang/vitepress-theme-teek/blob/master/plugins/vitepress-plugin-md-h1/src/types.ts)。 ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { mdH1Option: { /** 配置项 */ }, }, }); ``` ## vitepress-plugin-catalogue `vitepress-plugin-catalogue` 插件会将所有 `frontmatter.catalogue` 为 true 的文档信息挂载到 `themeConfig.catalogues` 中,Teek 使用该数据来生成目录页。 该插件与 Teek 强绑定,无法像上面的组件一样,通过 `vitePlugins.catalogue = false` 来禁用。 如果想要禁用该插件,只能通过禁用 Teek 主题来实现,配置如下: ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ teekTheme: false, // 禁用 Teek 主题 }); ``` 如果某个 markdown 文档不想被纳入目录里,则: ```yaml --- inCatalogue: false --- ``` ### 配置项 `catalogueOption` 的详细配置项请看 [Catalogue 配置项](https://github.com/Kele-Bingtang/vitepress-theme-teek/blob/master/plugins/vitepress-plugin-catalogue/src/types.ts)。 ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { catalogueOption: { /** 配置项 */ }, }, }); ``` ## vitepress-plugin-doc-analysis Teek 使用 `vitepress-plugin-doc-analysis` 来实现站点信息和文章页信息功能。 `vitepress-plugin-doc-analysis` 在 VitePress 启动后,扫描所有的 Markdown 文档,然后统计文章数量,文章字数等,最终将分析后的数据挂载到 `themeConfig.docAnalysisInfo` 中。 在首页看到的站点信息、文章页看到的文章字数、预计阅读时间等,都是使用 `themeConfig.docAnalysisInfo` 的数据来构成。 如果不希望某个 Markdown 文档被插件分析,请在该文档 `frontmatter` 配置: ```yaml --- docAnalysis: false --- ``` 如果想要禁用该插件,进行如下配置: ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { docAnalysis: false, }, }); ``` 关于文章的预计阅读时间的计算,该插件默认 1 分钟内阅读的中文字数为 300,1 分钟内阅读的英文字数为 160,如果认为不合理,可以对其进行修改: ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { docAnalysisOption: { cn: 400, en: 200, }, }, }); ``` ### 国际化 当处于国际化环境下,插件将不同语言的数据挂载到 `locales.[lang].themeConfig.docAnalysisInfo`。 ### 配置项 `docAnalysisOption` 的详细配置项请看 [DocAnalysis 配置项](https://github.com/Kele-Bingtang/vitepress-theme-teek/blob/master/plugins/vitepress-plugin-doc-analysis/src/types.ts)。 ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { docAnalysisOption: { /** 配置项 */ }, }, }); ``` ## vitepress-plugin-file-content-loader Teek 使用 `vitepress-plugin-file-content-loader` 来构建首页的文章列表和归档页数据,并挂载到 `themeConfig.posts` 中。 该插件本质上将 VitePress 官网的 [构建时数据加载](https://vitepress.dev/zh/guide/data-loading) 功能转为插件,因此具体的介绍说明请前往 VitePress 官网阅读。 ::: info 为什么设计为插件? 构建时数据加载功能是在访问网站的时候开始执行,如果使用该功能扫描了大量的 Markdown 文档,那么会导致第一次进入页面卡顿,因此基于该功能实现了插件,在项目启动过程完成数据的加载。 ::: 该插件与 Teek 强绑定,如果想要禁用该插件,只能通过禁用 Teek 主题来实现,配置如下: ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ teekTheme: false, // 禁用 Teek 主题 }); ``` ### 国际化 当处于国际化环境下,插件将不同语言的数据挂载到 `themeConfig.posts.locales.[lang]` 下。 ### 配置项 通过 `fileContentLoaderIgnore` 配置项告诉插件扫描 Markdown 文档时,指定忽略路径,格式为 glob 表达式,如 `test/\*\*` ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { fileContentLoaderIgnore: [], }, }); ``` ## vitepress-plugin-auto-frontmatter Teek 使用 `vitepress-plugin-auto-frontmatter` 自动给 Markdown 文档添加 `frontmatter`。 该插件会直接修改 Markdown 文档的 `frontmatter`,因此为了安全性考虑,默认是关闭的,如果希望开启,进行如下配置: ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { autoFrontmatter: true, }, }); ``` 如果开启了该插件,那么 Teek 将会对所有 Markdown 文档的 `frontmatter` 添加如下格式: ```yaml --- title: getting date: 2025-03-03 00:45:16 permalink: /pages/eb8f2f categories: - guide --- ``` * `title` 为文章的标题 * `date` 为文章的创建时间 * `permalink` 为文章的永久链接,采用随机数确保唯一 * `categories` 为文章的分类,根据目录层级获取 ::: tip Teek 不会修改已经存在的数据,判断的规则是比较 key,不比较 value。 ::: 如果需要拓展自定义 `frontmatter`,让 Teek 在生成 `frontmatter` 的时候额外添加其他数据,请使用 `transform` 配置项,具体使用请看 [vitepress-plugin-auto-frontmatter](https://github.com/Kele-Bingtang/vitepress-theme-teek/blob/master/plugins/vitepress-plugin-auto-frontmatter/README.md) 的 `Example 2` 和 `Example 3`。 ### 配置项 `autoFrontmatterOption` 的详细配置项请看 [AutoFrontmatter 配置项](https://github.com/Kele-Bingtang/vitepress-theme-teek/blob/master/plugins/vitepress-plugin-auto-frontmatter/src/types.ts)。 Teek 在 `vitepress-plugin-auto-frontmatter` 的配置项基础上额外添加两个配置项: * permalinkPrefix:自动生成 `permalink` 的固定前缀,如 `pages`、`pages/demo`,默认为 `pages` * categories:是否自动生成 `categories` ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { autoFrontmatter: true, autoFrontmatterOption: { permalinkPrefix: "pages", // 自动生成 permalink 的固定前缀,如 pages、pages/demo,默认为 pages categories: true, // 是否自动生成 categories // ... }, }, }); ``` --- --- url: /15.主题开发/80.Vite 插件.md --- # Vite 插件 VitePress 处于 Vite 环境下,因此天然支持 Vite 插件。 Teek 有过一个想法,那就是将所有功能完全插件化,通过 `NPM` 下载各个插件来合并成主题: * 目录页插件 * 归档页插件 * 文章信息插件 * Footer 插件 * ... 这完全是可行的,每个插件都是独立的,支持任何 VitePress 项目。 但是目前没有太多精力去实现这个计划,您可以通过 Teek 的按需引入功能(等价于下载插件),来加载自己需要的功能。 在了解 Vite 插件实现之前,建议您先去 [Vite 官方文档](https://cn.vite.dev) 了解什么是 Vite。 下面介绍在 VitePress 中自定义 Vite 插件的场景。 ## Vite 插件基础模板 首先介绍 Vite 插件的基础模板: ```ts import type { Plugin } from "vite"; interface Options { // ... } export default function VitePluginVitePressTemplate(option: Options = {}): Plugin { return { name: "vite-plugin-vitepress-template", // ... }; } ``` Vite 插件本质是一个函数,需要返回一个对象,对象的各个 Key 就是 Vite 提供的钩子,比如 `transform`、`config` 等,我们需要识别这些钩子分别执行了哪部分逻辑,这样才能针对性的实现自己的功能。 Vite 提供了哪些钩子请看官网 [插件 API](https://cn.vite.dev/guide/api-plugin.html#config)。 ## 扫描项目文件 如果您使用了 Teek 主题,那么在项目启动时,终端会打印: ```sh Injected Sidebar Data Successfully. 注入侧边栏数据成功! Injected Permalinks Data Successfully. 注入永久链接数据成功! Injected DocAnalysisInfo Data Successfully. 注入文档分析数据成功! Injected Catalogues Data Successfully. 注入目录页数据成功! Injected posts Data Successfully. 注入 posts 数据成功! ``` 每一行都是一个 Vite 插件输出的内容,这些插件都是去扫描项目的 Markdown 文件,然后生成数据并注入到 VitePress 的 `themeConfig` 中。 扫描项目文件的目的有如下场景: * 生成侧边栏:根据 Markdown 文件路径生成侧边栏数据 * 解析 Markdown 文档的 `frontmatter` 来生成文章信息,或给 Markdown 文件自动添加 `frontmatter` * 解析 Markdown 文档的内容,生成站点信息功能(总字数、文章字数、阅读时长等) * ... 这里需要用到 Vite 提供的 `config` 钩子,在解析 VitePress 配置前会调用该钩子,因此我们在这个钩子里执行扫描项目文件的逻辑,最后将数据注入到 VitePress 的 `themeConfig` 中。 ```ts import type { Plugin } from "vite"; interface Options { // ... } export default function VitePluginVitePressDemo(option: Options = {}): Plugin & { name: string } { return { name: "vitepress-plugin-demo", config(config: any) { // 获取 themeConfig 配置 const { site: { themeConfig = {} }, srcDir, } = config.vitepress; // 使用 node API 扫描项目文件,项目文件的根路径为 srcDir const data = scanProjectFiles(srcDir); themeConfig.demo = data; }, }; } const scanProjectFiles = (srcDir: string) => {}; ``` 这里就不详细介绍 `scanProjectFiles` 的逻辑,您可以阅读 Teek 的 Vite 插件源码来了解具体实现。 ## 加载功能组件 开头说的可以将各个功能完全插件化,就是利用插件来往 VitePress 的插槽中插入组件。 Vite 提供的 `load`、`transform`、`resolveId` 等钩子,是在访问某个资源的时候被调用,比如在浏览器访问某个页面时,我们可以通过这些钩子拦截到页面的代码,然后进行内容加工再返回给浏览器渲染。 因此当进入 VitePress 页面时,我们可以拦截 VitePress 的 `Layout` 组件,然后将自己实现的组件插入到插槽中,最后返回给浏览器渲染。 VitePress 提供了哪些插槽请看 [布局插槽](https://vitepress.dev/zh/guide/extending-default-theme#layout-slots)。 比如自定义一个组件插入到 `Layout` 的 `layout-top` 插槽中。 ::: code-group ```ts [index.ts] const isESM = () => { return typeof __filename === "undefined" || typeof __dirname === "undefined"; }; const getDirname = () => { return isESM() ? dirname(fileURLToPath(import.meta.url)) : __dirname; }; // 插件名 const componentName = "MyComponent"; const componentFile = `${componentName}.vue`; const aliasComponentFile = `${getDirname()}/components/${componentFile}`; const virtualModuleId = "virtual:my-component-option"; const resolvedVirtualModuleId = `\0${virtualModuleId}`; export function VitePluginVitePressMyNotFound( option: { notFoundDelayLoad?: number; } = {} ): Plugin & { name: string } { return { name: "vite-plugin-vitepress-my-not-found", config() { return { resolve: { alias: { [`./${componentFile}`]: aliasComponentFile, }, }, }; }, resolveId(id: string) { if (id === virtualModuleId) return resolvedVirtualModuleId; }, load(id: string) { // 使用虚拟模块将 option 传入组件里 if (id === resolvedVirtualModuleId) return `export default ${JSON.stringify(option)}`; // 在 Layout.vue 插槽插入自定义组件 if (id.endsWith("vitepress/dist/client/theme-default/Layout.vue")) { // 读取原始的 Vue 文件内容 const code = readFileSync(id, "utf-8"); // 插入自定义组件 const slotName = "layout-top"; const slotPosition = ``; const setupPosition = ' ``` ::: 插件通过虚拟模块将 `option` 配置传入到 `virtual:my-component-option` 中,因此可以在组件里引入。虚拟模块的内容请看 Vite 官网 [虚拟模块相关说明](https://cn.vite.dev/guide/api-plugin.html#virtual-modules-convention) 上面 `index.ts` 给出的代码模板具有通用性,你只需要: * 将 `const componentName = "MyComponent";` 改为要插入的组件名 * 将 `const slotName = "layout-top";` 改为要插入的插槽名 ::: tip 为什么不用 `transform` 钩子? `transform` 钩子返回的资源内容已经过 rollup 编译过,不再是源内容,因此无法找到插槽位置,一个解决方案是使用 `load` 钩子。 ::: ## unbuild 构建 unbuild 是一个用于构建库和工具的现代构建工具,由 `UnJS` 团队开发和维护。它旨在简化构建过程,提供高效的打包和构建功能,特别适用于构建 JavaScript 和 TypeScript 项目。 Teek 使用 unbuild 构建 VitePress 插件,这里仅介绍 unbuild 的 `entries` 配置项,其他 unbuild 的配置项请看 [unbuild 文档](https://unbuild.unjs.io/guide/configuration)。 ::: warning 如果插件在 node 环境下运行,需要构建为 `js` 相关文件,如果在 `client` 环境下运行,则可以保留 `ts`、`vue` 等文件。 VitePress 的 `.vitepress/config.mts` 在 `node` 环境运行,因此 `config.mts` 文件引入的第三方依赖必须是 `js` 相关文件,在 `.vitepress/theme/index.ts` 文件则可以引入 `ts`、`vue` 等不需要构建的文件。 ::: ### 入口文件 如果插件仅只有一个入口文件 `index.ts`,则 unbuild 的配置文件内容如下所示: ```ts // unbuild.config.ts import { defineBuildConfig } from "unbuild"; export default defineBuildConfig({ entries: ["src/index"], // ... }); ``` 等于: ```ts // unbuild.config.ts import { defineBuildConfig } from "unbuild"; export default defineBuildConfig({ entries: [{ builder: "rollup", input: "src/index", outDir: "dist" }], // ... }); ``` 后者比较灵活,可以指定输出的位置 `outDir`。 ::: tip 如果您觉得 `input` 或 `outDir` 的 `src/index`、`dist` 不易于阅读,可以改成 `./src/index` 和 `./dist`。 ::: ### Vue 组件 如果插件有 vue 组件,则 unbuild 的配置文件内容如下所示: ```ts // unbuild.config.ts import { defineBuildConfig } from "unbuild"; export default defineBuildConfig({ entries: [ { builder: "mkdist", input: "src/components", outDir: "dist/components", pattern: ["**/*.vue"], loaders: ["vue"] }, ], // ... }); ``` `mkdist` 是一个用于构建 Vue 组件的 unbuild 插件,它将 Vue 组件转换为 CommonJS 和 ESM 格式,并支持 TypeScript,它会保留源目录解构。 因此可以不使用 `outDir` 选项,`outDir` 默认为 `dist`,因此它会自动将 components 目录下的文件复制到 dist 目录下。 ### mkdist 构建多个类型文件 如果插件需要构建多个类型文件,则 unbuild 的配置文件内容如下所示: ```ts // unbuild.config.ts import { defineBuildConfig } from "unbuild"; export default defineBuildConfig({ entries: [ { builder: "mkdist", input: "src", outDir: "dist", pattern: ["**/*.ts"], format: "cjs", loaders: ["js"] }, { builder: "mkdist", input: "src", outDir: "dist", pattern: ["**/*.ts"], format: "esm", loaders: ["js"] }, { builder: "mkdist", input: "src", outDir: "dist", pattern: ["**/*.css"], loaders: ["postcss"] }, ], // ... }); ``` ### 静态目录 如果插件有一个静态文件目录 `assets` 需要复制到输出目录下,则 unbuild 的配置文件内容如下所示: ```ts // unbuild.config.ts import { defineBuildConfig } from "unbuild"; export default defineBuildConfig({ entries: [{ builder: "copy", input: "src/assets", outDir: "./dist/assets" }], // ... }); ``` 使用 `copy` 功能,`input` 只能是目录。 ### 使用 rollup 插件 如果你需要一些额外的 `rollup` 插件打包,则 unbuild 的配置文件内容如下所示: ```ts // unbuild.config.ts import { defineBuildConfig } from "unbuild"; import RollupPlugin from "rollup-plugin"; export default defineBuildConfig({ entries: [{ builder: "rollup", input: "src", outDir: "dist" }], hooks: { "rollup:options": (_, options) => { if (Array.isArray(options.plugins)) options.plugins.push(RollupPlugin); }, }, // ... }); ``` `hooks` 是 unbuild 的一个高级配置项,unbuild 会在指定的阶段调用 `hooks` 中的钩子,和 Vite 插件的钩子函数一样。 比如你希望在构建成功后,将一些文件 `copy` 到输出目录中,则可以使用 `hooks` 的 `buildEnd` 钩子,并安装 `fs-extra` 工具实现 `copy`。 ```ts import { defineBuildConfig } from "unbuild"; import { copy } from "fs-extra"; export default defineBuildConfig({ entries: ["src/index"], hooks: { "build:done": async () => { await copy("src/xx.d.ts", "dist/xx.d.ts"); }, }, }); ``` ### externals `externals` 是一个数组,用于指定不需要构建的依赖包,它将直接从外部引入,而不是构建到输出目录中。 当你使用了第三方依赖 如 vue、vite 等,需要将这些依赖添加到 `externals` 中,否则它们将被构建到输出目录中,导致依赖非常大。 ```ts // unbuild.config.ts import { defineBuildConfig } from "unbuild"; import RollupPlugin from "rollup-plugin"; export default defineBuildConfig({ externals: ["vue", "vite"], // ... }); ``` 其他项目使用您的插件时,如何确保这些在 `externals` 被排除的依赖正确安装呢?毕竟没有这些依赖,插件将无法运行。 您可以在 `package.json` 的 `dependencies` 中添加这些依赖,这些第三方依赖就会跟随你的插件一起安装到项目里。 ::: tip `devDependencies` 是开发依赖,不会随着插件一起安装到项目里,因此需要您斟酌哪些第三方依赖是运行必须的,则放到 `dependencies` 里,哪些是开发时必须的,则放到 `devDependencies` 里。 ::: --- --- url: /30.生态/03.公共组件/VpContainer 容器.md --- # VpContainer 容器 这是一个基于 VitePress 容器进行封装的组件,效果和 VitePress 容器一致。 ## 基础用法 ::: demo vpContainer/basic ::: ## API ### 属性 | 属性名 | 说明 | 类型 | 默认值 | | :----- | :--- | :------------------------------------ | :----- | | type | 类型 | `info` / `tip` / `warning` / `danger` | tip | | title | 标题 | `string` | — | | text | 文本 | `string` | — | ### 插槽 | 插槽名 | 说明 | | :------ | :--------------------------- | | default | 文本,覆盖 props 传来的 text | --- --- url: /01.指南/10.使用/15.主题增强.md --- # 主题增强 Teek 内置了 4 种布局模式、12 种主题色板可供切换,请将鼠标移到右上角的主题增强面板进行体验。 ## 布局模式 4 种布局模式分别为: * `fullWidth`:全部展开,使侧边栏和内容区域占据整个屏幕的全部宽度 * `sidebarWidthAdjustableOnly`:全部展开,侧边栏宽度可调,但内容区域宽度不变,调整后的侧边栏将可以占据整个屏幕的最大宽度 * `bothWidthAdjustable`:全部展开,侧边栏和内容区域宽度均可调,调整后的侧边栏和内容区域将可以占据整个屏幕的最大宽度 * `original`:原始的 VitePress 默认布局宽度 可以通过主题配置的 `themeEnhance.layoutSwitch.defaultMode` 来覆盖默认值,默认为 `original`。 ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ themeEnhance: { layoutSwitch: { defaultMode: "bothWidthAdjustable", }, }, }); ``` 当处于 `bothWidthAdjustable` 布局模式下,您可以控制默认的页面最大宽度和内容最大宽度。 ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ themeEnhance: { layoutSwitch: { defaultMode: "bothWidthAdjustable", defaultDocMaxWidth: 90, defaultPageMaxWidth: 90, }, }, }); ``` ::: tip `defaultDocMaxWidth` 和 `defaultPageMaxWidth` 的值仅限 0-100。 ::: * 如果希望禁用布局模式切换功能,可以设置 `themeEnhance.layoutSwitch.disable` 为 `true` * 如果希望隐藏布局模式切换功能(不允许用户手动切换),可以设置 `themeEnhance.layoutSwitch.hidden` 为 `true` 两个区别在于,`hidden` 只是隐藏该功能,您仍然可以设置其他配置默认值,只是在页面禁止用户手动切换配置。 ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ themeEnhance: { layoutSwitch: { disabled: true, // hidden: true, }, }, }); ``` ## 主题色板 12 种主题色板分别为 `vp-primary`、`vp-success`、`vp-warning`、`vp-danger`、`tk-primary`、`tk-success`、`tk-warning`、`tk-danger`、`ep-primary`、`ep-success`、`ep-warning`、`ep-danger`。 其中 `vp-` 开头的使用 VitePress 内置的主题色板,`tk-` 开头的使用 Teek 的主题色板,`ep-` 开头的使用 ElementPlus 的主题色板。 可以通过主题配置的 `themeEnhance.themeColor.defaultColorName` 来覆盖默认值,默认为 `vp-primary`。 ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ themeEnhance: { themeColor: { defaultColorName: "ep-primary", }, }, }); ``` * 如果希望禁用主题色板切换功能,可以设置 `themeEnhance.themeColor.disable` 为 `true` * 如果希望隐藏主题色板切换功能(不允许用户手动切换),可以设置 `themeEnhance.themeColor.hidden` 为 `true` ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ themeEnhance: { themeColor: { disable: true, // hidden: true, }, }, }); ``` ## 聚光灯 可以通过主题配置的 `themeEnhance.spotlight.defaultValue` 来覆盖默认值,默认为 `true`。 ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ themeEnhance: { spotlight: { defaultValue: true, }, }, }); ``` * 如果希望禁用藏聚光灯功能,可以设置 `themeEnhance.spotlight.disable` 为 `true` * 如果希望隐藏藏聚光灯功能(不允许用户手动切换),可以设置 `themeEnhance.spotlight.hidden` 为 `true` ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ themeEnhance: { spotlight: { disable: true, // hidden: true, }, }, }); ``` ## 文档单独配置 Teek 支持在 Markdown 的 `frontmatter` 单独进行如下配置来覆盖全局的设置。 ```yaml --- layoutMode: bothWidthAdjustable themeColorName: ep-primary spotlight: false --- ``` ## 功能参考 * [阅读增强](https://github.com/nolebase/integrations/blob/main/packages/vitepress-plugin-enhanced-readabilities/README.md) --- --- url: /10.配置/40.主题增强拓展.md --- # 主题增强拓展 ## 主题色板 在 [主题增强](/guide/theme-enhance) 中介绍了主题色板的使用,而不同的用户有不同的审美需求,因此 Teek 支持用户修改自带的主题色板,也可以拓展全新的主题色板。 ### 主题色板修改 Teek 使用 VitePress 的 `css var` 变量来实现主题色板。当切换尺寸时,Teek 会修改 `html` 标签的 `theme-color` 属性,进而改变 `css var` 变量,从而达到修改主题色板的效果。 如果觉得 Teek 提供的主题色板不符合自己的风格,可以修改不同 `theme-color` 下对应的 `css var` 变量来达到目的。 Teek 主题色板的 `css var` 变量如下: ```scss @use "../mixins/function" as *; /* VitePress 成功色 */ html[theme-color="vp-success"] { --vp-c-brand-1: var(--vp-c-success-1); --vp-c-brand-2: var(--vp-c-success-2); --vp-c-brand-3: var(--vp-c-success-3); --vp-c-brand-soft: var(--vp-c-success-soft); } /* VitePress 警告色 */ html[theme-color="vp-warning"] { --vp-c-brand-1: var(--vp-c-warning-1); --vp-c-brand-2: var(--vp-c-warning-2); --vp-c-brand-3: var(--vp-c-warning-3); --vp-c-brand-soft: var(--vp-c-warning-soft); } /* VitePress 危险色 */ html[theme-color="vp-danger"] { --vp-c-brand-1: var(--vp-c-danger-1); --vp-c-brand-2: var(--vp-c-danger-2); --vp-c-brand-3: var(--vp-c-danger-3); --vp-c-brand-soft: var(--vp-c-danger-soft); } /* element plus 品牌色 */ html[theme-color="tk-primary"] { --vp-c-brand-1: #{getCssVar(color-primary)}; --vp-c-brand-2: #{getCssVar(color-primary-light-3)}; --vp-c-brand-3: #{getCssVar(color-primary-light-5)}; --vp-c-brand-soft: #{getCssVar(color-primary-light-8)}; } /* element plus 成功色 */ html[theme-color="tk-success"] { --vp-c-brand-1: #{getCssVar(color-success)}; --vp-c-brand-2: #{getCssVar(color-success-light-3)}; --vp-c-brand-3: #{getCssVar(color-success-light-5)}; --vp-c-brand-soft: #{getCssVar(color-success-light-8)}; } /* element plus 警告色 */ html[theme-color="tk-warning"] { --vp-c-brand-1: #{getCssVar(color-warning)}; --vp-c-brand-2: #{getCssVar(color-warning-light-3)}; --vp-c-brand-3: #{getCssVar(color-warning-light-5)}; --vp-c-brand-soft: #{getCssVar(color-warning-light-8)}; } /* element plus 危险色 */ html[theme-color="tk-danger"] { --vp-c-brand-1: #{getCssVar(color-danger)}; --vp-c-brand-2: #{getCssVar(color-danger-light-3)}; --vp-c-brand-3: #{getCssVar(color-danger-light-5)}; --vp-c-brand-soft: #{getCssVar(color-danger-light-8)}; } /* element plus 品牌色 */ html[theme-color="tk-primary"] { --vp-c-brand-1: #{getCssVar(el-color-primary)}; --vp-c-brand-2: #{getCssVar(el-color-primary-light-3)}; --vp-c-brand-3: #{getCssVar(el-color-primary-light-5)}; --vp-c-brand-soft: #{getCssVar(el-color-primary-light-8)}; } /* element plus 成功色 */ html[theme-color="ep-success"] { --vp-c-brand-1: #{getCssVar(el-color-success)}; --vp-c-brand-2: #{getCssVar(el-color-success-light-3)}; --vp-c-brand-3: #{getCssVar(el-color-success-light-5)}; --vp-c-brand-soft: #{getCssVar(el-color-success-light-8)}; } /* element plus 警告色 */ html[theme-color="ep-warning"] { --vp-c-brand-1: #{getCssVar(el-color-warning)}; --vp-c-brand-2: #{getCssVar(el-color-warning-light-3)}; --vp-c-brand-3: #{getCssVar(el-color-warning-light-5)}; --vp-c-brand-soft: #{getCssVar(el-color-warning-light-8)}; } /* element plus 危险色 */ html[theme-color="ep-danger"] { --vp-c-brand-1: #{getCssVar(el-color-danger)}; --vp-c-brand-2: #{getCssVar(el-color-danger-light-3)}; --vp-c-brand-3: #{getCssVar(el-color-danger-light-5)}; --vp-c-brand-soft: #{getCssVar(el-color-danger-light-8)}; } ``` ::: tip `--vp-c-brand-1` 为 VitePress 的核心主题色,在修改或者拓展时,您应该考虑优先修改该 var 变量。 ::: 您可以创建一个 `css` 文件来修改上面提供的变量,如在 `vp-success` 主题色板下修改 `--vp-c-brand-1` 变量: ```css [tk-theme-color.css] html[theme-color="vp-success"] { --vp-c-brand-1: #395ae3; } ``` 在 `.vitepress/theme/index.ts` 文件引入该 `css` 文件: ```ts [index.ts] {3} import Teek from "vitepress-theme-teek"; import "vitepress-theme-teek/index.css"; import "./style/tk-theme-color.css"; export default { extends: Teek, }; ``` 这样在 `vp-success` 主题色板下,`--vp-c-brand-1` 变量被设置为 `#395AE3`。 ### 主题色板拓展 在右上角的主题增强面板可以看到 Teek 内置的 12 个主题色板,除此之外,Teek 支持额外追加自定义的主题色板。 有两种方式自定义主题色板 #### 预设主题变量 首先在 `scss` 文件定义自定义主题色板的 `css var` 变量 如添加 `github` 主题色板: ```scss html[theme-color="github-blue"] { --vp-c-brand-1: xx; --vp-c-brand-2: xx; --vp-c-brand-3: xx; --vp-c-brand-soft: xx; // ...... 修改其他 VitePress 提供的 css var 变量 } html[theme-color="github-green"] { --vp-c-brand-1: xxx; --vp-c-brand-2: xxx; --vp-c-brand-3: xxx; --vp-c-brand-soft: xxx; // ...... 修改其他 VitePress 提供的 css var 变量 } ``` 在 `.vitepress/theme/index.ts` 文件引入该 `css` 文件: ```ts [index.ts] {3} import Teek from "vitepress-theme-teek"; import "vitepress-theme-teek/index.css"; import "./style/tk-theme-color.css"; export default { extends: Teek, }; ``` 然后通过主题配置的 `themeEnhance.themeColor.append` 追加自定义主题色板,如: ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ themeEnhance: { themeColor: { append: [ { label: "Github 主题", // 主题组名称 tip: "Github 主题", // 主题组提示信息,鼠标悬停时显示 options: [ { label: "风格 1", value: "github-blue" }, { label: "风格 2", value: "github-green" }, ], }, ], }, }, }); ``` 这样您就可以在主题增强面板里看到注册的 `Github` 主题。 #### 预设主色 第一种方式需要提前在 `html` 的 `theme-color` 属性上提前预设好 4 个颜色,然后在主题增强面板点击主题色板更新 `html` 的 `theme-color` 值,从而修改 `css var` 变量达到目的。 第二种方式更加简单,只需要指定一个主色 `color`,Teek 通过内置的算法自动计算出其他颜色。 ```ts {11-18} import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ themeEnhance: { themeColor: { append: [ { label: "博客扩展主题", // 主题组名称 tip: "博客扩展主题", // 主题组提示信息,鼠标悬停时显示 options: [ { label: "紫罗兰", value: "violet", color: "#7166f0" }, { label: "珊瑚粉", value: "coral-pink", color: "#ff6b6b" }, { label: "天蓝", value: "sky-blue", color: "#00bbf9" }, { label: "蓝绿", value: "blue-green", color: "#00f5d4" }, { label: "石板灰", value: "slate-gray", color: "#708090" }, { label: "粉红", value: "pink", color: "#f15bb5" }, { label: "黄绿", value: "yellow-green", color: "#8ac926" }, { label: "橙红", value: "orange-red", color: "#ff9e6b" }, ], }, ], }, }, }); ``` ### 主题色板扩散 您可以在主题增强面板看到 扩散 单选框,激活后 Teek 将根据 `--vp-c-brand-1` 自动计算出其他颜色,然后扩散到全局。 ## 主题尺寸 Teek 使用 `css var` 变量来实现主题尺寸。当切换尺寸时,Teek 会修改 `html` 标签的 `theme-size` 属性,进而改变 `css var` 变量,从而达到修改主题尺寸的效果。 如果觉得 Teek 提供的主题尺寸不符合自己的风格,可以修改不同 `theme-size` 下对应的 `css var` 变量来达到目的。 ::: tip 主题尺寸仅作用在 Teek 的首页已经自定义页,不会修改 VitePress 的默认主题。 ::: Teek 主题尺寸的 `css var` 变量如下: ```scss @use "../mixins/mixins" as *; @use "../mixins/function" as *; html[tk-theme-size="wide"] { @include set-css-var(home-max-width, 1420px); @include set-css-var(home-gap, getCssVar(gap3)); @include set-css-var(home-post-simple-img-width, 160px); @include set-css-var(home-post-full-img-width, 480px); @include set-css-var(home-post-full-img-height, 100%); @include set-css-var(home-post-line-clamp, 4); @include set-css-var(home-card-padding, 15px); @include set-css-var(home-card-width, 350px); @include set-css-var(home-card-svg-margin-left, 10px); @include set-css-var(home-font-size-large, 19px); @include set-css-var(home-font-size-base, 17px); @include set-css-var(home-font-size-middle, 15px); @include set-css-var(home-font-size-sm, 14px); @include set-css-var(home-font-size-small, 13px); @include set-css-var(home-page-width, 1100px); @include set-css-var(home-footer-group-width, 100%); } html[tk-theme-size="large"] { @include set-css-var(home-max-width, 1330px); @include set-css-var(home-gap, getCssVar(gap3)); @include set-css-var(home-post-simple-img-width, 160px); @include set-css-var(home-post-full-img-width, 420px); @include set-css-var(home-post-full-img-height, 100%); @include set-css-var(home-post-line-clamp, 4); @include set-css-var(home-card-padding, 15px); @include set-css-var(home-card-width, 350px); @include set-css-var(home-card-svg-margin-left, 10px); @include set-css-var(home-font-size-large, 19px); @include set-css-var(home-font-size-base, 17px); @include set-css-var(home-font-size-middle, 15px); @include set-css-var(home-font-size-sm, 14px); @include set-css-var(home-font-size-small, 13px); @include set-css-var(home-page-width, 1000px); @include set-css-var(home-footer-group-width, 90%); } :root, html[tk-theme-size="default"] { @include set-css-var(home-max-width, 1140px); @include set-css-var(home-gap, getCssVar(gap2)); @include set-css-var(home-post-simple-img-width, 120px); @include set-css-var(home-post-simple-img-height, 80px); @include set-css-var(home-post-full-img-width, 360px); @include set-css-var(home-post-full-img-height, 100%); @include set-css-var(home-post-line-clamp, 3); @include set-css-var(home-card-padding, 10px); @include set-css-var(home-card-width, 280px); @include set-css-var(home-card-svg-margin-left, 5px); @include set-css-var(home-card-border-radius, 4px); @include set-css-var(home-font-size-large, 18px); @include set-css-var(home-font-size-base, 16px); @include set-css-var(home-font-size-middle, 14px); @include set-css-var(home-font-size-sm, 13px); @include set-css-var(home-font-size-small, 12px); @include set-css-var(page-width, 900px); @include set-css-var(home-footer-group-width, 80%); } html[tk-theme-size="small"] { @include set-css-var(home-max-width, 1000px); @include set-css-var(home-gap, getCssVar(gap2)); @include set-css-var(home-post-simple-img-width, 100px); @include set-css-var(home-post-simple-img-height, 80px); @include set-css-var(home-post-full-img-width, 240px); @include set-css-var(home-post-full-img-height, 100%); @include set-css-var(home-post-line-clamp, 2); @include set-css-var(home-card-padding, 8px); @include set-css-var(home-card-width, 260px); @include set-css-var(home-card-svg-margin-left, 4px); @include set-css-var(home-font-size-large, 17px); @include set-css-var(home-font-size-base, 15px); @include set-css-var(home-font-size-middle, 13px); @include set-css-var(home-font-size-sm, 13px); @include set-css-var(home-font-size-small, 12px); @include set-css-var(page-width, 800px); @include set-css-var(home-footer-group-width, 70%); } @media (min-width: 768px) { :root, html[tk-theme-size="large"], html[tk-theme-size="default"], html[tk-theme-size="small"] { @include set-css-var(home-card-width, 280px); } } @media (max-width: 768px) { :root, html[tk-theme-size="large"], html[tk-theme-size="default"], html[tk-theme-size="small"] { @include set-css-var(home-card-width, 100%); } } ``` 您可以创建一个 `css` 文件来修改上面提供的变量,如在 `default` 尺寸下,将 `--tk-home-max-width` 变量设置为 `1280px`: ```css [tk-theme-size.css] :root, html[tk-theme-size="default"] { --tk-home-max-width: 1280px; /* 将 1140px 改为 1280px */ } ``` 在 `.vitepress/theme/index.ts` 文件引入该 `css` 文件: ```ts {3} import Teek from "vitepress-theme-teek"; import "vitepress-theme-teek/index.css"; import "./style/tk-theme-size.css"; export default { extends: Teek, }; ``` 这样 `default` 尺寸下,`--tk-home-max-width` 变量被设置为 `1280px`。 --- --- url: /15.主题开发/10.主题配置.md --- # 主题配置 在主题开发中,往往需要提供一些配置来丰富主题的功能,最简单的是和 VitePress 的 `themeConfig` 配置合在一起: ```ts {8} // .vitepress/config.mts import { defineConfig } from "vitepress"; export default defineConfig({ // ... themeConfig: { // vitepress 配置 // 自定义主题配置 }, }); ``` 然后在组件里通过 `useData` 获取 `themeConfig` 的内容: ```vue ``` 这种方式仅适合简单的主题,当主题需要添加一个 `head` 或者 `vite` 插件,需要让用户修改 VitePress 的配置,这样极其不方便。 因此可以先将主题配置抽离出来,然后使用 `extends` 来合并主题配置。 ## extends 合并配置 VitePress 提供了 `extends` 来合并外界传来的配置项,比如外界的配置提供了部分 `head` 内容,并且在 VitePress 也配置了 `head`,则最终合并为一个全新的 head,而不是覆盖。 :::tip VitePress 的配置项只有为对象/数组时可以合并,如果配置项为一个固定的值或者函数,则以 VitePress 的配置项为主。 ::: `extends` 合并主题配置的使用方式如下: ```ts {4,8} import { defineConfig } from "vitepress"; // 主题配置 const teekConfig = {}; // vitepress 配置 export default defineConfig({ extends: teekConfig, // ... themeConfig: { // ... }, }); ``` 在 VitePress 配置中通过 `extends` 可以将主题配置合并到 VitePress 配置里,也就是说完全可以在主题配置里添加 VitePress 的配置项,但是不能反过来,如: ::: code-group ```ts [各自配置] // .vitepress/config.mts import { defineConfig } from "vitepress"; // 主题配置 const myThemeConfig = { themeConfig: { teekTheme: true } }; // VitePress 配置 export default defineConfig({ extends: myThemeConfig, base: "/", }); ``` ```ts [统一配置] // .vitepress/config.mts import { defineConfig } from "vitepress"; // 主题配置 + VitePress 配置 const myThemeConfig = { base: "/", themeConfig: { teekTheme: true } }; export default defineConfig({ extends: myThemeConfig, }); ``` ::: ## 函数式构建配置 在主题配置里,如果要使用 Vite 插件或者想要修改 VitePress 默认的配置,则可以提供一个函数来返回主题配置: ```ts // myThemeConfig.ts import type { DefaultTheme, UserConfig } from "vitepress"; import type { PluginOption } from "vite"; interface ThemeConfig { useTheme?: boolean; // 是否开启主题 // ... } export default function getThemeConfig(config: ThemeConfig & UserConfig = {}): UserConfig { // 获取用户的配置,进行逻辑处理 const { useTheme = true, ...themeConfig } = config; if (!useTheme) return {}; return { // ignoreDeadLinks 默认值修改为 true,当用户在 VitePress 手动改为 false 才为 false ignoreDeadLinks: true, // 添加主题需要的 head 信息 head: [], vite: { // 添加主题需要的 Vite 插件 plugins: [], }, themeConfig, }; } ``` 在 `.vitepress/config.mts` 引入该函数: ```ts import { defineConfig } from "vitepress"; import getThemeConfig from "myThemeConfig"; const myThemeConfig = getThemeConfig({ useTheme: false }); // VitePress 配置 export default defineConfig({ extends: myThemeConfig, // ... }); ``` --- --- url: /10.配置/01.主题配置/05.全局配置.md --- # 全局配置 全局配置是影响范围较广的配置。 ## teekTheme * 类型:`boolean` * 默认值:`true` 是否启用 Teek 主题,如果为 false,则不会启用主题的 99% 功能,只保留如下功能: * 自动添加侧边栏 * 自动添加一级标题 * 自动添加永久链接 * 文档内容分析(作者、创建时间、文章字数、预计阅读时间等信息) * 锚点滚动 * 深色/浅色模式过渡动画 ::: tip 如果您仍然想要关闭保留的部分功能,Teek 也提供了相关配置项来关闭,请继续往下阅读保留功能的配置项。 ::: 配置如下: ```ts // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ teekTheme: true, }); ``` ::: tip 如果想全部清除 Teek 的功能,那么在 `.vitepress/theme/index.ts` 文件里去掉 Teek 引用。 ::: ## teekHome * 类型:`boolean` * 默认值:`true` 是否启用 Teek 的首页风格(博客风格),如果为 false,则还原到 VitePress 的默认首页,其他功能不变。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ teekHome: true, }); ``` ```yaml [index.md] --- tk: teekHome: true --- ``` ::: ## vpHome * 类型:`boolean` * 默认值:`true` 是否启用 VitePress 首页风格,支持 `teekHome` 和 `vpHome` 同时存在。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vpHome: true, }); ``` ```yaml [index.md] --- tk: vpHome: true --- ``` ::: ## loading * 类型:`boolean` | `string` * 默认值:`false` 页面加载 Loading 动画配置,如果为 `boolean`,则控制是否启用,如果为字符串,则指定加载 Loading 动画的文案。 ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ loading: true, // 启用 Loading 动画,为 false 则关闭 Loading 动画 // loading: "正在加载中...", // 修改 Loading 文案 }); ``` ## features 站点特性列表,在文档风格的首页展渲染,与 VitePress 的 `features` 配置模板一致,但是不会与 VitePress 的 `features` 配置渲染冲突。 该配置项 Teek 建议在首页 `index.md` 文档里的 `frontmatter.tk.features` 进行配置。 每一个 `feature` 的 `icon` 为 [TkIcon](/guide/icon-use) Props 的 `icon` 属性,支持传入 `iconfont`、`SVG`、图片等图标。 ::: code-group ```yaml [index.md] tk: teekHome: false features: - title: 快速开发 details: 提供了完整版参考代码和精简版开发代码 image: /feature/ui.svg highlights: - title: 从零安装:运行 pnpm add vitepress-theme-teek vitepress 以从 NPM 下载 Teek 主题。 - title: 现有模板:运行 git clone https://github.com/Kele-Bingtang/vitepress-theme-teek-docs-template.git 以下载当前文档模板。 - title: 拥有丰富的 Features,并持续更新 details: 满足大部分开发场景。 image: /feature/features.svg features: - title: 最新流行稳定技术栈 icon: icon-github details: 基于 Vue3.2、TypeScript、Vite4、Pinia、Element-Plus 等最新技术栈开发 link: /guide/intro - title: 简单上手 & 学习 icon: details: 项目结构清晰,代码简单、易读。 - title: 规范工程化工作流 icon: /teek-logo-mini.svg details: 配置 Eslint、Prettier、Husky、Commitlint、Lint-staged 规范前端工程代码规范。 - title: 完善的打包优化方案 icon: icon-github details: 内置规范的打包目录,提供打包压缩功能,减少打包体积。 - title: 丰富的组件 icon: /teek-logo-mini.svg details: 提供丰富的通用组件、业务组件。 link: /ecosystem/components - title: 常用 Hook 函数 icon: icon-gitee details: 提供丰富的组件、常用 Hooks 封装,实现复用思想,减少重复开发,提高效率。 - title: 个性化主题配置 icon: icon-xiangce details: 提供主题颜色配置,暗黑、灰色、色弱等模式切换。 link: /guide/theme-enhance - title: 多种布局配置 icon: /teek-logo-mini.svg details: 提供多种布局、标签栏切换,布局显隐,满足大部分场景。 - title: 项目权限管控 icon: /teek-logo-mini.svg details: 采用 RBAC 权限管控,提供菜单、路由及按钮粗细粒度权限管理方案 - title: 国际化 icon: /teek-logo-mini.svg details: 内置常用国际化转换函数,支持自定义国际化切换, - title: IFrame 嵌入 icon: /teek-logo-mini.svg details: 提供 IFrame 嵌入、缓存功能,支持门户 Portal 布局。 - title: 自定义指令 icon: /teek-logo-mini.svg details: 内置多种 Vue 自定义指令,提供傻瓜式指令一键注册功能。 - title: Axios 封装 icon: /teek-logo-mini.svg details: 基于 Axios 封装常用请求模块,内置业务拦截器、异常拦截器。 - title: 多种图标类型 icon: /teek-logo-mini.svg details: 支持 IconFont、SVG、Iconify 等多种图标类型渲染。 link: /guide/icon-use - title: 布局 details: 多种布局、标签栏切换,布局组件显隐 image: /feature/layout.svg highlights: - title: 六大布局 icon: /teek-logo-mini.svg details: 内置纵向、经典、横向、分栏、混合、子系统六大布局切换 - title: 深色模式 icon: /teek-logo-mini.svg details: 可以自由切换浅色模式与深色模式 - title: 主题色切换 icon: /teek-logo-mini.svg details: 支持自定义主题色并允许用户在预设的主题颜色之间切换 - title: 布局组件 icon: /teek-logo-mini.svg details: 支持图标、面包屑、导航栏等组件显隐,内置缓存功能,记住用户的布局配置 ``` ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ features: [ { title: "快速开发", details: "提供了完整版参考代码和精简版开发代码", image: "/feature/ui.svg", highlights: [ { title: "从零安装:运行 pnpm add vitepress-theme-teek vitepress 以从 NPM 下载 Teek 主题。", }, { title: "现有模板:运行 git clone https://github.com/Kele-Bingtang/vitepress-theme-teek-docs-template.git 以下载当前文档模板。", }, ], }, { title: "拥有丰富的 Features,并持续更新", details: "满足大部分开发场景。", image: "/feature/features.svg", features: [ { title: "最新流行稳定技术栈", icon: "icon-github", details: "基于 Vue3.2、TypeScript、Vite4、Pinia、Element-Plus 等最新技术栈开发", link: "/guide/intro", }, { title: "简单上手 & 学习", icon: '', details: "项目结构清晰,代码简单、易读。", }, { title: "规范工程化工作流", icon: "/teek-logo-mini.svg", details: "配置 Eslint、Prettier、Husky、Commitlint、Lint-staged 规范前端工程代码规范。", }, { title: "完善的打包优化方案", icon: "icon-github", details: "内置规范的打包目录,提供打包压缩功能,减少打包体积。", }, { title: "丰富的组件", icon: "/teek-logo-mini.svg", details: "提供丰富的通用组件、业务组件。", link: "/ecosystem/components", }, { title: "常用 Hook 函数", icon: "icon-gitee", details: "提供丰富的组件、常用 Hooks 封装,实现复用思想,减少重复开发,提高效率。", }, { title: "个性化主题配置", icon: "icon-xiangce", details: "提供主题颜色配置,暗黑、灰色、色弱等模式切换。", link: "/guide/theme-enhance", }, { title: "多种布局配置", icon: "/teek-logo-mini.svg", details: "提供多种布局、标签栏切换,布局显隐,满足大部分场景。", }, { title: "项目权限管控", icon: "/teek-logo-mini.svg", details: "采用 RBAC 权限管控,提供菜单、路由及按钮粗细粒度权限管理方案", }, { title: "国际化", icon: "/teek-logo-mini.svg", details: "内置常用国际化转换函数,支持自定义国际化切换,", }, { title: "IFrame 嵌入", icon: "/teek-logo-mini.svg", details: "提供 IFrame 嵌入、缓存功能,支持门户 Portal 布局。", }, { title: "自定义指令", icon: "/teek-logo-mini.svg", details: "内置多种 Vue 自定义指令,提供傻瓜式指令一键注册功能。", }, { title: "Axios 封装", icon: "/teek-logo-mini.svg", details: "基于 Axios 封装常用请求模块,内置业务拦截器、异常拦截器。", }, { title: "多种图标类型", icon: "/teek-logo-mini.svg", details: "支持 IconFont、SVG、Iconify 等多种图标类型渲染。", link: "/guide/icon-use", }, ], }, { title: "布局", details: "多种布局、标签栏切换,布局组件显隐", image: "/feature/layout.svg", highlights: [ { title: "六大布局", icon: "/teek-logo-mini.svg", details: "内置纵向、经典、横向、分栏、混合、子系统六大布局切换", }, { title: "深色模式", icon: "/teek-logo-mini.svg", details: "可以自由切换浅色模式与深色模式", }, { title: "主题色切换", icon: "/teek-logo-mini.svg", details: "支持自定义主题色并允许用户在预设的主题颜色之间切换", }, { title: "布局组件", icon: "/teek-logo-mini.svg", details: "支持图标、面包屑、导航栏等组件显隐,内置缓存功能,记住用户的布局配置", }, ], }, ], }); ``` ```ts [更多配置项] import type { IconProps } from "@teek/components/common/icon/src/icon"; interface Feature { /** * 标题 */ title: string; /** * 描述 */ details?: string; /** * 图片地址 */ image?: string; /** * Features 数据 */ features?: FeatureItem[]; /** * Highlights 数据 */ highlights?: FeatureItem[]; } interface FeatureItem { /** * 标题 */ title: string; /** * 描述 */ details?: string; /** * 图标地址 */ icon?: IconProps["icon"]; /** * 点击跳转链接 */ link?: string; } ``` ::: ## anchorScroll * 类型:`boolean` * 默认值:`true` 是否启用锚点滚动功能,即阅读文章时,自动将 `h1 ~ h6` 标题添加到地址栏 `#` 后面。 ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ anchorScroll: true, }); ``` ## themeSize * 类型:`small` | `default` | `large` | `wide` * 默认值:`default` 配置主题尺寸。只影响 Teek 主题首页和功能页,不影响 VitePress 默认主题。 ```ts // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ themeSize: "default", }); ``` 如果你认为这些主题尺寸不够用,你可以自定义主题尺寸。 下面是 themeSize 为 `default` 时的的样式,你可以复制到一个 css 文件里,然后修改并在 `.vitepress/theme/index.ts` 文件中引入,这就会覆盖默认的样式。 ```css :root, html[#{$namespace}-theme-size="default"] { --tk-home-max-width: 1140px; --tk-home-gap: 20px; --tk-home-post-simple-img-width: 120px; --tk-home-post-simple-img-height: 80px; --tk-home-post-full-img-width: 360px; --tk-home-post-full-img-height: 100%; --tk-home-post-line-clamp: 3; --tk-home-card-padding: 10px; --tk-home-card-width: 280px; --tk-home-card-svg-margin-left: 5px; --tk-home-card-border-radius: 4px; --tk-home-font-size-large: 18px; --tk-home-font-size-base: 16px; --tk-home-font-size-middle: 14px; --tk-home-font-size-sm: 13px; --tk-home-font-size-small: 12px; --tk-page-width: 900px; --tk-home-footer-group-width: 80%; } ``` 如果您认为首页的文章列表和卡片栏在高尺寸的屏幕显得很窄,则可以单独修改 `--tk-home-max-width` 来达到效果,如: ```css :root { --tk-home-max-width: calc(100% - 100% / 3); // 这里给的是一个响应式公式,100% 为屏幕宽度,请自行修改为自己认为合适的大小 } ``` 记得在 `.vitepress/theme/index.ts` 文件中引入生效。 ## viewTransition 深色、浅色模式切换过渡动画配置。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ viewTransition: { enabled: true, // 是否启用深浅色切换动画效果 mode: "out-in", // 动画模式,out 始终从点击点往全屏扩散,out-in 第一次从点击点往全屏扩散,再次点击从全屏回到点击点 duration: 300, // 动画持续时间,当 mode 为 out 时,默认为 300ms,mode 为 out-in 时,默认为 600ms easing: "ease-in", // 缓动函数 }, }); ``` ```ts [更多配置项] interface ViewTransition { /** * 是否启用深浅色切换动画效果 * * @default true */ enabled?: boolean; /** * 动画模式,out 始终从点击点往全屏扩散,out-in 第一次从点击点往全屏扩散,再次点击从全屏回到点击点 * * @default 'out-in' */ mode?: "out" | "out-in"; /** * 动画持续时间,当 mode 为 out 时,默认为 300ms,mode 为 out-in 时,默认为 600ms * * @default 'out-in: 300ms, out-in: 600ms' */ duration?: number; /** * 缓动函数 * * @default 'ease-in' */ easing?: string; } ``` ::: ## backTop 右下角回到顶部配置。 如果希望将实时数字换成一个火箭图标,则将 `backTop.content` 设置为 `icon`。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ backTop: { enabled: true, // 是否启动回到顶部功能 content: "progress", // 回到顶部按钮的显示内容,可选配置 progress | icon done: TkMessage => TkMessage.success("返回顶部成功"), // 回到顶部后的回调 }, }); ``` ```ts [更多配置项] import { Message } from "@teek/components/common/Message/src/message"; interface BackTop { /** * 是否启动回到顶部功能 * * @default true */ enabled?: boolean; /** * 回到顶部按钮的显示内容 * * @default 'progress' */ content?: "progress" | "icon"; /** * 回到顶部后的回调 */ done?: (TkMessage: Message) => void; } ``` ::: 如果想重写回到顶部的组件,则使用 [teek-back-top](/guide/slot#全局插槽) 插槽。 ## toComment 右下角滚动滚动到评论区配置。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ toComment: { enabled: true, // 是否启动滚动到评论区功能 done: TkMessage => TkMessage.success("已抵达评论区"), // 滚动到评论区后的回调 }, }); ``` ```ts [更多配置项] import { Message } from "@teek/components/common/Message/src/message"; interface ToComment { /** * 是否启动滚动到评论区功能 * * @default true */ enabled?: boolean; /** * 滚动到评论区后的回调 */ done?: (TkMessage: Message) => void; } ``` ::: 如果想重写滚动滚动到评论区的组件,则使用 [teek-to-comment](/guide/slot#全局插槽) 插槽。 ## codeBlock 新版代码块配置,您现在看到的代码块是新版代码块。 ::: tip 在 `details` 容器下或父元素的 class 为 `tk-vp-code` 时,恢复为 VitePress 的默认代码块风格。 ::: ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ codeBlock: { enabled: true, // 是否启用新版代码块 collapseHeight: 700, // 超出高度后自动折叠,设置 true 则默认折叠,false 则默认不折叠 overlay: false, // 代码块底部是否显示展开/折叠遮罩层 overlayHeight: 400, // 当出现遮罩层时,指定代码块显示高度,当 overlay 为 true 时生效 langTextTransform: "uppercase", // 语言文本显示样式,为 text-transform 的值:none, capitalize, lowercase, uppercase copiedDone: TkMessage => TkMessage.success("复制成功!"), // 复制代码完成后的回调 }, }); ``` ```yaml [文章页 xxx.md] --- codeBlock: disabled: false collapseHeight: 700 --- ``` ```ts [更多配置项] interface CodeBlock { /** * 是否启用新版代码块 * * @default true */ enabled?: boolean; /** * 超出高度后自动折叠,设置 true 则默认折叠,false 则默认不折叠 * * @default 700 */ collapseHeight?: number | boolean; /** * 复制代码完成后的回调 */ copiedDone?: (TkMessage: Message) => void; /** * 代码块底部是否显示展开/折叠遮罩层 * * @default false * @since 1.4.0 */ overlay?: boolean; /** * 当出现遮罩层时,指定代码块显示高度,当 overlay 为 true 时生效 * * @default 400 * @since 1.4.0 */ overlayHeight?: number; /** * 语言文本显示样式,为 text-transform 的值 * * none:文本中的单词保持默认风格 * capitalize:文本中的每个单词以大写字母开头 * lowercase:文本中的每个单词全部转为小写 * uppercase:定文本中的单次全部转为大写 * * @default 'uppercase' */ langTextTransform?: "none" | "capitalize" | "lowercase" | "uppercase"; } ``` ::: 新版代码块的语言默认为大写,如果希望为小写或者首字母大写,有两种方式: 1. 通过在 `config.mts` 配置 `codeBlock.langTextTransform`,其原理是内部实现第二种方式来达到目标 2. 通过修改 `css var` 变量的 `tk-code-block-lang-transform` 来达成目标 ::: tip `tk-code-block-lang-transform` 的值等于 CSS 中 `text-transform` 的值。 ::: 先定义一个 `css` 文件: ```css [tk-code-style.css] /* .vitepress/theme/style/tk-code-style.css */ :root { /* * none:文本中的单词保持默认风格 * capitalize:文本中的每个单词以大写字母开头 * lowercase:文本中的每个单词全部转为小写 * uppercase:定文本中的单次全部转为大写 */ --tk-code-block-lang-transform: lowercase; } ``` 在 `.vitepress/theme/index.ts` 文件引入该 `css` 文件: ```ts {4} // .vitepress/theme/index.ts import Teek from "vitepress-theme-teek"; import "vitepress-theme-teek/index.css"; import "./style/tk-code-style.css"; export default { extends: Teek, }; ``` ## sidebarTrigger * 类型:`boolean` * 默认值:`false` 是否启用侧边栏展开/折叠触发器,点击触发器可以展开/折叠侧边栏。 ```ts // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ sidebarTrigger: false, }); ``` 如果想重写侧边栏展开/折叠触发器组件,则使用 [teek-sidebar-trigger](/guide/slot#全局插槽) 插槽。 ## windowTransition * 类型:`boolean` / `object` * 默认值:`true` 是否全局给部分元素启用视图渐入过渡效果,当为 `boolean` 类型,则控制全局是否启用,当为 `object` 类型,则控制部分元素是否启用。 `object` 为 `WindowTransition` 类型,请看下方代码块的 更多配置项。 ::: tip 什么是视图渐入过渡效果 当第一次进入博客风格的首页或者归档页时,向下滚动,会看到每一个元素的从下方向上移动的过渡效果。 ::: ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ windowTransition: true, }); ``` ```ts [更多配置项] interface TeekConfig { /** * 是否全局启用视图渐入过渡效果 * * @default true */ windowTransition?: boolean | WindowTransition; } interface WindowTransition { /** * 是否开启首页文章列表过渡效果 * * @default false */ post?: boolean; /** * 是否开启首页卡片列表过渡效果 * * @default false */ card?: boolean; /** * 是否开启归档页过渡效果 * * @default false */ archives?: boolean; } ``` ::: ## bodyBgImg body 背景图片配置,将整个网站的背景色改为图片。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ bodyBgImg: { imgSrc: ["/img/bg1.jpg", "/img/bg2.png"], // body 背景图片链接。单张图片 string | 多张图片 string[], 多张图片时每隔 imgInterval 秒换一张 imgOpacity: 1, // body 背景图透明度,选值 0.1 ~ 1.0 imgInterval: 15000, // body 当多张背景图时(imgSrc 为数组),设置切换时间,单位:毫秒 imgShuffle: false, // body 背景图是否随机切换,为 false 时按顺序切换 mask: false, // body 背景图遮罩 maskBg: "rgba(0, 0, 0, 0.2)", // body 背景图遮罩颜色,如果为数字,则是 rgba(0, 0, 0, ${maskBg}),如果为字符串,则作为背景色。mask 为 true 时生效 }, }); ``` ```yaml [文章页 xx.md] --- bodyBgImg: imgSrc: - /img/bg1.jpg - /img/bg2.png imgOpacity: 1 imgInterval: 15000 imgShuffle: false mask: false maskBg: "rgba(0, 0, 0, 0.2)" --- ``` ```ts [更多配置项] interface BodyBgImg { /** * body 背景图片链接。单张图片 string | 多张图片 string[], 多张图片时每隔 imgInterval 秒换一张 */ imgSrc?: string | string[] | (() => string | string[]); /** * body 背景图透明度,选值 0.1 ~ 1.0 * * @default 1 */ imgOpacity?: 0.1 | 0.2 | 0.3 | 0.4 | 0.5 | 0.6 | 0.7 | 0.8 | 0.9 | 1; /** * body 当多张背景图时(imgSrc 为数组),设置切换时间,单位:毫秒 * * @default 15000 (15秒) */ imgInterval?: number; /** * body 背景图是否随机切换,为 false 时按顺序切换 * * @default false */ imgShuffle?: boolean; /** * body 背景图遮罩 * * @default false */ mask?: boolean; /** * body 背景图遮罩颜色,如果为数字,则是 rgba(0, 0, 0, ${maskBg}),如果为字符串,则作为背景色。mask 为 true 时生效 * * @default 'rgba(0, 0, 0, 0.2)' */ maskBg?: string | number; } ``` ::: ::: tip `bodyBgImg` 设置了 `imgSrc` 后,`banner` 的图片风格会失效。 ::: ## themeEnhance 主题增强配置,当开启后,右上角将有主题增强面板出现。 关于主题增强详细的介绍请看 [主题增强](/guide/theme-enhance)。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ themeEnhance: { enabled: true, // 启用主题增强功能 position: "top", // 位置,top 为导航栏右侧,bottom 为右下角 // 布局切换配置 layoutSwitch: { disabled: false, // 禁用布局切换 hidden: false, // 隐藏布局切换 defaultMode: "original", // 布局切换的默认模式 disableHelp: false, // 禁用帮助提示 disableAnimation: false, // 禁用布局切换动画 defaultDocMaxWidth: 90, // 内容布局最大宽度的默认百分比,仅限 0-100 disableDocMaxWidthHelp: false, // 禁用帮助提示 defaultPageMaxWidth: 95, // 页面布局最大宽度的默认百分比,仅限 0-100 disablePageMaxWidthHelp: false, // 禁用帮助提示 }, // 布局主题色配置 themeColor: { disabled: false, // 禁用布局主题色切换 hidden: false, // 隐藏布局主题色切换 defaultColorName: "vp-primary", // 布局默认主题色 defaultSpread: false, // 是否将主题色扩散到其他元素(根据主题色计算其他元素需要的颜色) disableHelp: false, // 禁用帮助提示 disabledInMobile: false, // 是否在移动端禁用 }, // 聚光灯配置 spotlight: { disabled: false, // 禁用聚光灯 hidden: false, // 隐藏聚光灯 defaultStyle: "aside", // 聚光灯默认样式 disableHelp: false, // 禁用帮助提示 defaultValue: true, // 聚光灯默认开关状态 }, }, }); ``` ```ts [更多配置项] import type { ThemeColorName, LayoutMode, SpotlightStyle } from "vitepress-theme-teek"; interface ThemeEnhance { /** * 启用主题增强功能 * * @default true * @since 1.4.0 */ enabled?: boolean; /** * 隐藏主题增强功能,但是仍然可以设置默认值 * * @default false * @since 1.5.8 */ hidden?: boolean; /** * 位置,top 为导航栏右侧,bottom 为右下角 * * @default 'top' */ position?: "top" | "bottom"; /** * 布局切换配置 */ layoutSwitch?: { /** * 禁用布局切换 * * @default false */ disabled?: boolean; /** * 隐藏布局切换配置,但是仍然可以设置默认值 * * @default false * @since 1.5.8 */ hidden?: boolean; /** * 布局切换的默认模式 * * @default LayoutMode.Original */ defaultMode?: LayoutMode | LayoutModeVal; /** * 切换布局成功后的回调 * * @since 1.3.2 */ switchModeDone?: (mode: LayoutMode | LayoutModeVal) => void; /** * 禁用帮助提示 * * @default false */ disableHelp?: boolean; /** * 禁用布局切换动画 * * @default false */ disableAnimation?: boolean; /** * 内容布局最大宽度的默认百分比,仅限 0-100 * * @default 90 (90%) */ defaultDocMaxWidth?: number; /** * 禁用帮助提示 * * @default false */ disableDocMaxWidthHelp?: boolean; /** * 页面布局最大宽度的默认百分比,仅限 0-100 * * @default 95 (95%) */ defaultPageMaxWidth?: number; /** * 禁用帮助提示 * * @default false */ disablePageMaxWidthHelp?: boolean; }; /** * 布局主题色配置 */ themeColor?: { /** * 禁用布局主题色切换 * * @default false */ disabled?: boolean; /** * 隐藏布局主题色配置,但是仍然可以设置默认值 * * @default false * @since 1.5.8 */ hidden?: boolean; /** * 从 0 完全自定义布局主题色,不使用内置主题色 * * @default false * @since 1.4.1 */ customize?: boolean; /** * 布局默认主题色 * * @default ThemeColorName.vpPrimary */ defaultColorName?: | ThemeColorName | "vp-primary" | "vp-success" | "vp-warning" | "vp-danger" | "tk-primary" | "tk-success" | "tk-warning" | "tk-danger" | "ep-primary" | "ep-success" | "ep-warning" | "ep-danger" | string; /** * 切换布局成功后的回调 * * @since 1.3.2 */ switchColorDone?: (color: string) => void; /** * 是否将主题色扩散到其他元素(根据主题色计算其他元素需要的颜色) * * @default false */ defaultSpread?: boolean; /** * 禁用帮助提示 * * @default false */ disableHelp?: boolean; /** * 是否在移动端禁用 * * @default false */ disabledInMobile?: boolean; /** * 自定义主题色,将会追加到内置主题色后面 */ append?: { /** * 主题组名称 */ label: string; /** * 主题组提示信息,鼠标悬停时显示 */ tip?: string; /** * 主题组内容 */ options: ThemeColorOption[]; }[]; }; /** * 聚光灯配置 */ spotlight?: { /** * 禁用聚光灯 * * @default false */ disabled?: boolean; /** * 隐藏聚光灯配置,但是仍然可以设置默认值 * * @default false * @since 1.5.8 */ hidden?: boolean; /** * 聚光灯默认样式 * * @default SpotlightStyle.Aside */ defaultStyle?: SpotlightStyle | "aside" | "under"; /** * 禁用帮助提示 * * @default false */ disableHelp?: boolean; /** * 聚光灯默认开关状态 * * @default true */ defaultValue?: boolean; }; } ``` ::: 如果想去掉主题增强面板的内置主题色板,可以使用 `themeEnhance.themeColor.customize` 配置项。 该配置项为 `false` 时,将关闭 Teek 所有内置的主题色,此时你可以通过 `themeEnhance.themeColor.append` 自定义添加自己的主题色。 ```ts {7,9-12} // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ themeEnhance: { themeColor: { customize: false, // 关闭内置主题色 }, }, }); ``` 如果想拓展自己的主题色,请看 [主题增强拓展](/reference/theme-enhance)。 ## author 文章默认的作者信息。 在首页的文章列表和文章页使用该功能。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ author: { name: "Teeker", // 作者名称 link: "https://github.com/Kele-Bingtang", // 点击作者名称后跳转的链接 }, }); ``` ```yaml [文章页 xx.md] --- author: name: "Teeker" link: "https://github.com/Kele-Bingtang", --- ``` ```ts [更多配置项] interface Author { /** * 作者名称,作用在首页的 PostItem 和文章页 */ name: string; /** * 点击作者名称后跳转的链接 */ link?: string; } ``` ::: ## notice 公告配置。 公告组件只提供基础功能,不提供任何内容的渲染,需要您自定义组件,然后在 `.vitepress/theme/index.ts` 中通过 `teek-notice-content` 插槽传进来。 使用如下: ```ts [插槽] // .vitepress/theme/index.ts import Teek from "vitepress-theme-teek"; import "vitepress-theme-teek/index.css"; import MyNoticeContent from "./components/MyNoticeContent.vue"; import { h } from "vue"; export default { extends: Teek, Layout() { return h(Teek.Layout, null, { "teek-notice-content": () => h(MyNoticeContent), }); }, }; ``` 配置如下: ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ notice: { enabled: true, // 是否启用公告功能 title: "公告", // 公告标题,支持函数式:需要和国际化搭配使用,根据不同语言环境返回不同标题 initOpen: true, duration: 0, // 弹框定时自动关闭,0 不自动消失 mobileMinify: false, // 移动端自动最小化 reopen: true, useStorage: true, // 是是否使用 localStorage 存储公告状态,如:当打开公告弹框后,下次进来则自动打开弹框 twinkle: false, // 公告图标是否打开闪烁提示 position: "top", // 公告弹框出现位置 // ... }, }); ``` ```yaml [文章页 xx.md] --- notice: enabled: true title: "公告" initOpen: true duration: 0 mobileMinify: false reopen: true useStorage: true twinkle: false position: "top" --- ``` ````ts [更多配置项] import type { Route } from "vitepress"; import type { IconProps } from "vitepress-theme-teek"; interface Notice { /** * 是否启用公告功能 * * @default false */ enabled?: boolean; /** * 公告自定义全局样式 * * @example * ```css * .tk-notice a { * color: var(--vp-c-brand-2); * } * ``` */ noticeStyle?: string; /** * 公告图标样式 */ iconStyle?: Record; /** * 公告弹窗样式 */ popoverStyle?: Record; /** * 公告标题,函数式需要和国际化搭配使用,根据不同语言环境返回不同标题 * * @default '公告' */ title?: string | ((localeIndex: string) => string); /** * 第一次进入页面,是否默认打开公告弹框 * * @default true */ initOpen?: boolean; /** * 弹框定时自动关闭,0 不自动消失 * * @default 0 */ duration?: number; /** * 移动端自动最小化 * * @default false */ mobileMinify?: boolean; /** * 关闭公告弹框后,是否支持重新打开,如果为 false,则代表公告只显示一次 * * @default true */ reopen?: boolean; /** * 是否使用 localStorage 存储公告状态,如:当打开公告弹框后,下次进来则自动打开弹框 */ useStorage?: boolean; /** * 公告图标是否打开闪烁提示 * * @default false */ twinkle?: boolean; /** * 公告弹框出现位置 * * @default top */ position?: "top" | "center"; /** * 公告图标地址 * * @remark 与 noticeIconType 配合使用 */ noticeIcon?: IconProps["icon"]; /** * 公告弹框关闭图标地址,与 noticeIcon 配置一致 */ closeIcon?: IconProps["icon"]; /** * 路由切换后的自定义回调 * * @param to 切换到的目标路由 */ onAfterRouteChange?: (to: Route, noticeShow: boolean, showPopover: boolean) => void; } ```` ::: ## siteAnalytics 站点分析配置,目前集成了四种常见的站点统计工具: * 百度分析 `Baidu Analytics` * 谷歌分析 `Google Analytics` * 微软 Clarity `Microsoft Clarity` * `Umami` 分析 具体使用说明请看 [站点统计](/guide/statistics)。 使用如下: ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ siteAnalytics: [ { provider: "google", options: { id: "******", }, }, { provider: "baidu", options: { id: "******", }, }, { provider: "umami", options: { id: "******", src: "**", }, }, { provider: "clarity", options: { id: "******", }, }, ], }); ``` ```ts [更多配置项] import type { BaiduAnalyticsOptions, GoogleAnalyticsOptions, UmamiAnalyticsOptions, ClarityAnalyticsOptions, } from "vitepress-theme-teek"; type SiteAnalytics = { /** * 赞赏位置 */ provider: T; /** * 赞赏配置 */ options?: SiteAnalyticsProvider[T]; }; type SiteAnalyticsProvider = { "": object; baidu: BaiduAnalyticsOptions; google: GoogleAnalyticsOptions; umami: UmamiAnalyticsOptions; clarity: ClarityAnalyticsOptions; }; ``` ::: --- --- url: /01.指南/20.相关/10.写作排版.md --- # 写作排版 ::: tip 序言 统一中文文案、排版的相关用法,降低团队成员之间的沟通成本,增强网站气质 ::: ## 空格 「有研究显示,打字的时候不喜欢在中文和英文之间加空格的人,感情路都走得很辛苦,有七成的比例会在 34 岁的时候跟自己不爱的人结婚,而其余三成的人最后只能把遗产留给自己的猫。毕竟爱情跟书写都需要适时地留白。 与大家共勉之。 ::: right —— [vinta/paranoid-auto-spacing](https://github.com/vinta/pangu.js) ::: ### 中英文之间需要增加空格 正确: > 在 LeanCloud 上,数据存储是围绕 `AVObject` 进行的。 错误: > 在LeanCloud上,数据存储是围绕`AVObject`进行的。 > 在 LeanCloud上,数据存储是围绕`AVObject` 进行的。 完整的正确用法: > 在 LeanCloud 上,数据存储是围绕 `AVObject` 进行的。每个 `AVObject` 都包含了与 JSON 兼容的 key-value 对应的数据。数据是 schema-free 的,你不需要在每个 `AVObject` 上提前指定存在哪些键,只要直接设定对应的 key-value 即可。 例外:「豆瓣FM」等产品名词,按照官方所定义的格式书写。 ### 中文与数字之间需要增加空格 正确: > 今天出去买菜花了 5000 元。 错误: > 今天出去买菜花了 5000元。 > 今天出去买菜花了5000元。 ### 数字与单位之间无需增加空格 正确: > 我家的光纤入户宽带有 10Gbps,SSD 一共有 10TB。 错误: > 我家的光纤入户宽带有 10 Gbps,SSD 一共有 20 TB。 另外,度/百分比与数字之间不需要增加空格: 正确: > 今天是 233° 的高温。 > 新 MacBook Pro 有 15% 的 CPU 性能提升。 错误: > 今天是 233 ° 的高温。 > 新 MacBook Pro 有 15 % 的 CPU 性能提升。 ### 全角标点与其他字符之间不加空格 正确: > 刚刚买了一部 iPhone,好开心! 错误: > 刚刚买了一部 iPhone ,好开心! ### `-ms-text-autospace` to the rescue Microsoft 有个 [`-ms-text-autospace`](http://msdn.microsoft.com/en-us/library/ie/ms531164\(v=vs.85\).aspx) 的 CSS 属性可以实现自动为中英文之间增加空白。不过目前并未普及,另外在其他应用场景,例如 OS X、iOS 的用户界面目前并不存在这个特性,所以请继续保持随手加空格的习惯。 ## 标点符号 ### 不重复使用标点符号 正确: > 德国队竟然战胜了巴西队! > 她竟然对你说「喵」?! 错误: > 德国队竟然战胜了巴西队!! > 德国队竟然战胜了巴西队!!!!!!!! > 她竟然对你说「喵」??!! > 她竟然对你说「喵」?!?!??!! ## 全角和半角 不明白什么是全角(全形)与半角(半形)符号?请查看维基百科词条『[全角和半角](http://zh.wikipedia.org/wiki/全形和半形)』或者百度百科词条『[全角](https://baike.baidu.com/item/%E5%85%A8%E8%A7%92/9323113?fr=aladdin)』和『[半角](https://baike.baidu.com/item/半角)』。 简单介绍: 「**全角**」指一个字符占用两个标准字符位置的状态,如中文模式下的逗号、句号等:,。?「」 「**半角**」就是 ASCII 方式的字符,在没有中文输入法起作用的时候输入的字母数字和字符都是半角的,如英文模式下的逗号、句号等: , . ; ? "" ### 直角符号 英文单词使用 "" 或者 ''; 中文词语使用 「」或者『』,不使用弯角符号 “” 和 ‘’,弯角符号更适用于手写。 其中 "" 对应「」,'' 对应『』 ### 使用全角中文标点 正确: > 嗨!你知道嘛?今天前台的小妹跟我说「喵」了哎! > 核磁共振成像(NMRI)是什么原理都不知道?JFGI! 错误: > 嗨! 你知道嘛? 今天前台的小妹跟我说 "喵" 了哎! > 嗨!你知道嘛?今天前台的小妹跟我说"喵"了哎! > 核磁共振成像 (NMRI) 是什么原理都不知道? JFGI! > 核磁共振成像(NMRI)是什么原理都不知道?JFGI! ### 数字使用半角字符 正确: > 这件蛋糕只卖 1000 元。 错误: > 这件蛋糕只卖 1000 元。 例外:在设计稿、宣传海报中如出现极少量数字的情形时,为方便文字对齐,是可以使用全角数字的。 ### 遇到完整的英文整句、特殊名词,其內容使用半角标点 正确: > 乔布斯那句话是怎么说的?「Stay hungry, stay foolish.」 > 推荐你阅读《Hackers & Painters: Big Ideas from the Computer Age》,非常的有趣。 错误: > 乔布斯那句话是怎么说的?「Stay hungry,stay foolish。」 > 推荐你阅读《Hackers&Painters:Big Ideas from the Computer Age》,非常的有趣。 ## 名词 ### 专有名词使用正确的大小写 大小写相关用法原属于英文书写范畴,不属于本文档讨论內容,在这里只对部分易错用法进行简述。 正确: > 使用 GitHub 登录 > 我们的客户有 GitHub、Foursquare、Microsoft Corporation、Google、Facebook, Inc.。 错误: > 使用 github 登录 > 使用 GITHUB 登录 > 使用 Github 登录 > 使用 gitHub 登录 > 使用 gイんĤЦ8 登录 > 我们的客户有 github、foursquare、microsoft corporation、google、facebook, inc.。 > 我们的客户有 GITHUB、FOURSQUARE、MICROSOFT CORPORATION、GOOGLE、FACEBOOK, INC.。 > 我们的客户有 Github、FourSquare、MicroSoft Corporation、Google、FaceBook, Inc.。 > 我们的客户有 gitHub、fourSquare、microSoft Corporation、google、faceBook, Inc.。 > 我们的客户有 gイんĤЦ8、キouЯƧquムгє、๓เςг๏ร๏Ŧt ς๏гק๏гคtเ๏ภn、900913、ƒ4ᄃëв๏๏к, IПᄃ.。 注意:当网页中需要配合整体视觉风格而出现全部大写/小写的情形,HTML 中请使用标准的大小写规范进行书写;并通过 `text-transform: uppercase;`/`text-transform: lowercase;` 对表现形式进行定义。 ### 不要使用不地道的缩写 正确: > 我们需要一位熟悉 JavaScript、HTML5,至少理解一种框架(如 Backbone.js、AngularJS、React 等)的前端开发者。 错误: > 我们需要一位熟悉 Js、h5,至少理解一种框架(如 backbone、angular、RJS 等)的 FED。 ### 链接之间增加空格 用法: > 请 [提交一个 issue](https://github.com/mzlogin/chinese-copywriting-guidelines/blob/Simplified/README.md#) 并分配给相关同事。 > 访问我们网站的最新动态,请 [点击这里](https://github.com/mzlogin/chinese-copywriting-guidelines/blob/Simplified/README.md#) 进行订阅! 对比用法: > 请[提交一个 issue](https://github.com/mzlogin/chinese-copywriting-guidelines/blob/Simplified/README.md#) 并分配给相关同事。 > 访问我们网站的最新动态,请[点击这里](https://github.com/mzlogin/chinese-copywriting-guidelines/blob/Simplified/README.md#)进行订阅! ### 简体中文使用直角引号 用法: > 「老师,『有条不紊』的『紊』是什么意思?」 对比用法: > “老师,‘有条不紊’的‘紊’是什么意思?” ### 加粗文字增加空格 正确: > 一个好的 **排版** 彰显好的文档。 错误: > 一个好的**排版**彰显好的文档。 ### 加粗文字与标点符号 加粗的文字如果是最后一行,或者独处一行,那么加粗范围包括标点符号; 加粗的文字如果后面还有文字,则加粗范围不包括标点符号。 正确: > 欢迎来到我的博客,**请慢慢食用。** > **欢迎来到我的博客**,请慢慢食用。 错误: > 欢迎来到我的博客,**请慢慢食用**。 > > **欢迎来到我的博客,** 请慢慢食用。 可能看不太清楚,这里解释一下: * 错误的例子中,句号在加粗范围外面,逗号在加粗范围里面 * 正确的例子中,句号在加粗范围里面,逗号在加粗范围外面 ## 个人风格 以下用法略带有个人色彩,即:无论是否遵循下述规则,从语法的角度来讲都是 **正确** 的。 ### 体系化文档命名规范 正确: > 关于 - 技巧 > > 笔记 - 技巧 > > 排版 - 技巧 错误: > 关于技巧 > > 笔记 技巧 > > 排版 ~ 技巧 ### 体系化文档开头添加目录 生成可以跳转的目录,方便他人阅读和选择。 如 VitePress 可以解析 `[[TOC]]` 字符串从而生成目录。 ### 有序/无序列表末尾不加标点符合 因为开头的符号已经代表句号/感叹号/问号了。 正确: > * 欢迎来到 `Teek` > > * 希望能入你法眼 > > 1. 酒菜不多,但都是精华。请慢慢食用 > 2. 文章内容不恰当,可以在评论区留言 错误: > * 欢迎来到 `Teek`。 > > * 希望能入你法眼。 > > 1. 酒菜不多,但都是精华。请慢慢食用。 > 2. 文章内容不恰当,可以在评论区留言。 ## 格式化工具 使用这些工具,可以一次性把需要的文章按照工具的规定进行格式化,类似于杂乱的代码被格式化有序。 | 仓库 | 语言 | | ------------------------------------------------------------------------------------------------------------------------------- | --------------- | | [vinta/paranoid-auto-spacing](https://github.com/vinta/paranoid-auto-spacing) | JavaScript | | [huei90/pangu.node](https://github.com/huei90/pangu.node) | Node.js | | [huacnlee/auto-correct](https://github.com/huacnlee/auto-correct) | Ruby | | [sparanoid/space-lover](https://github.com/sparanoid/space-lover) | PHP (WordPress) | | [nauxliu/auto-correct](https://github.com/NauxLiu/auto-correct) | PHP | | [ricoa/copywriting-correct](https://github.com/ricoa/copywriting-correct) | PHP | | [hotoo/pangu.vim](https://github.com/hotoo/pangu.vim) | Vim | | [sparanoid/grunt-auto-spacing](https://github.com/sparanoid/grunt-auto-spacing) | Node.js (Grunt) | | [hjiang/scripts/add-space-between-latin-and-cjk](https://github.com/hjiang/scripts/blob/master/add-space-between-latin-and-cjk) | Python | ## 谁在这样做? | 网站 | 文案 | UGC | | ------------------------------------------------- | ---- | ------------ | | [Apple 中国](http://www.apple.com/cn/) | Yes | N/A | | [Apple 香港](http://www.apple.com/hk/) | Yes | N/A | | [Apple 台湾](http://www.apple.com/tw/) | Yes | N/A | | [Microsoft 中国](http://www.microsoft.com/zh-cn/) | Yes | N/A | | [Microsoft 香港](http://www.microsoft.com/zh-hk/) | Yes | N/A | | [Microsoft 台湾](http://www.microsoft.com/zh-tw/) | Yes | N/A | | [LeanCloud](https://leancloud.cn/) | Yes | N/A | | [知乎](https://www.zhihu.com/) | Yes | 部分用户达成 | | [V2EX](https://www.v2ex.com/) | Yes | Yes | | [SegmentFault](https://segmentfault.com/) | Yes | 部分用户达成 | | [Apple4us](http://apple4us.com/) | Yes | N/A | | [豌豆荚](https://www.wandoujia.com/) | Yes | N/A | | [Ruby China](https://ruby-china.org/) | Yes | 标题达成 | | [PHPHub](https://phphub.org/) | Yes | 标题达成 | | [少数派](http://sspai.com/) | Yes | N/A | | [力扣 LeetCode](https://leetcode-cn.com/) | Yes | Yes | ## 本文转载 添加了一些自己的理解 [中文文案排版指北](https://github.com/mzlogin/chinese-copywriting-guidelines/blob/Simplified/README.md) ## 参考文献 * [Guidelines for Using Capital Letters](http://grammar.about.com/od/punctuationandmechanics/a/Guidelines-For-Using-Capital-Letters.htm) * [Letter case - Wikipedia](http://en.wikipedia.org/wiki/Letter_case) * [Punctuation - Oxford Dictionaries](http://www.oxforddictionaries.com/words/punctuation) * [Punctuation - The Purdue OWL](https://owl.english.purdue.edu/owl/section/1/6/) * [How to Use English Punctuation Corrently - wikiHow](http://www.wikihow.com/Use-English-Punctuation-Correctly) * [格式 - openSUSE](https://zh.opensuse.org/index.php?title=Help:格式) * [全角和半角 - 维基百科](http://zh.wikipedia.org/wiki/全形和半形) * [引号 - 维基百科](http://zh.wikipedia.org/wiki/引號) * [疑问惊叹号 - 维基百科](http://zh.wikipedia.org/wiki/疑問驚嘆號) * [全角 - 百度百科](https://baike.baidu.com/item/%E5%85%A8%E8%A7%92/9323113?fr=aladdin) * [半角 - 百度百科](https://baike.baidu.com/item/%E5%8D%8A%E8%A7%92) --- --- url: /@pages/categoriesPage.md --- --- --- url: /10.配置/01.主题配置/50.功能页配置.md --- # 功能页配置 ## 私密文章(登录页) 什么是登录页?在导航栏 功能页 -> 登录页 点击查看效果。 您可以通过 `teek-login-page` 插槽自定义登录页。 使用登录页需要 2 个步骤: * 创建一个登录页,如何创建请看 [登录页](/reference/function-page#登录页) * 开启私密文章监听 ```ts // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ private: { enabled: true, }, }); ``` 此时已经开启了私密文章功能,下一步您需要配置登录相关的配置,如果要想了解所有配置请看 更多配置项。 这里仅仅给出一些配置项例子,有关私密文章更详细的设计、介绍、使用,请看 [私密文章](/guide/private) ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ private: { enabled: false, expire: "1d", session: true, siteLogin: false, site: [ { username: "teek-site-1", password: "teek", role: "common", expire: "1d", session: true, strategy: "once" }, { username: "teek-site-2", password: "teek", role: "admin", expire: "1d", session: false, strategy: "always" }, ], pages: [ { username: "teek-pages-1", password: "teek", expire: "1d", session: true, strategy: "once" }, { username: "teek-pages-2", password: "teek", expire: "1d", session: false, strategy: "always" }, ], realm: { blog: [ { username: "teek-blog-1", password: "teek", expire: "1d", session: true, strategy: "once" }, { username: "teek-blog-2", password: "teek", expire: "1d", session: false, strategy: "always" }, ], comment: [ { username: "teek-comment-1", password: "teek", expire: "1d", session: true, strategy: "always" }, { username: "teek-comment-2", password: "teek", expire: "1d", session: false, strategy: "always" }, ], }, // onFocus: (value, formName) => {}, // onBlur: (value, formName) => {}, // doLogin: (loginInfo, type, nativeExecLogin) => true, // doValidate: (type, frontmatter, nativeExecLogin) => true, // encrypt: (value, frontmatter) => value, // decrypt: (value, frontmatter) => value, }, }); ``` ```ts [更多配置项] interface Private { /** * 是否启用私密功能 * * @default false */ enabled?: boolean; /** * 登录过期时间:1d 代表 1 天,1h 代表 1 小时,仅支持这两个单位,不加单位代表秒。过期后访问私密文章重新输入用户名和密码。默认一天 * * @default '1d' */ expire?: string; /** * 开启是否在网页关闭或刷新后,清除登录状态,这样再次访问网页,需要重新登录 * * @default false */ session?: boolean; /** * 是否使用站点级别登录功能,即第一次进入网站需要验证 * * @default false */ siteLogin?: boolean; /** * 站点级别登录信息,进入站点时需要认证,当 siteLogin 为 true 时生效 */ site?: (LoginInfo & { role?: "common" | "admin" })[]; /** * 全局页面级登录信息,登录一次后其他全局页面级别的文章都可以访问 */ pages?: LoginInfo[]; /** * 领域页面级别登录信息,登录一次后其他相同领域的文章都可以访问 */ realm?: { [key: string]: LoginInfo[] }; /** * 输入框聚焦回调 */ onFocus?: (value: string, formName: "username" | "password" | "verifyCode") => void; /** * 输入框失焦回调 */ onBlur?: (value: string, formName: "username" | "password" | "verifyCode") => void; /** * 自定义登录逻辑,如果返回 boolean 代表自定义逻辑成功或者失败(内部会删除提示语),返回 undefined 代表结束登录逻辑 * * @param nativeExecLogin 内置的登录函数,通过调用该函数来实现内置的登录功能 */ doLogin?: ( loginInfo: { username: string; password: string }, type: "site" | "pages" | "realm" | "page", nativeExecLogin: () => boolean ) => boolean | undefined; /** * 自定义验证逻辑 * * @param nativeExecLogin 内置的登录函数,通过调用该函数来实现内置的登录功能 */ doValidate?: ( type: "site" | "pages" | "realm" | "page", frontmatter: Record, nativeValidate: () => boolean ) => boolean; /** * 自定义加密逻辑 */ encrypt?: (value: string, frontmatter: Record) => string; /** * 自定义解密逻辑 */ decrypt?: (value: string, frontmatter: Record) => string; } interface LoginInfo { /** * 用户名 */ username: string; /** * 密码 */ password: string; /** * 登录过期时间:1d 代表 1 天,1h 代表 1 小时,仅支持这两个单位,不加单位代表秒。过期后访问私密文章重新输入用户名和密码。默认一天 * * @default 1d */ expire?: string; /** * 开启是否在网页关闭或刷新后,清除登录状态,这样再次访问网页,需要重新登录 * * @default false */ session?: boolean; /** * 登录策略,once 代表一次登录,always 代表每次访问都登录 * * @default 'once' */ strategy?: "once" | "always"; } ``` ::: ## 风险链接提示页 什么是风险链接提示页?在导航栏 功能页 -> 风险链接提示页 点击查看效果。 您可以通过 `teek-risk-link-page` 插槽自定义险链接提示页。 使用风险链接提示页需要 2 个步骤: * 创建一个风险链接提示页,如何创建请看 [风险链接提示页](/reference/function-page#风险链接提示页) * 开启监听外部链接跳转拦截功能(监听 `a` 标签的点击事件) ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ riskLink: { enabled: true, }, }); ``` ```ts [更多配置项] interface RiskLink { /** * 是否启用风险链接提示功能 * * @default false */ enabled?: boolean; /** * 白名单,支持正则表达式 */ whitelist?: Array; /** * 黑名单,支持正则表达式 * * @remark 如果设置了黑名单,则只拦截黑名单的链接 */ blacklist?: Array; } ``` ::: 此时 Teek 会监听所有 `a` 标签的点击事件,如果点击的链接是风险链接,则会先跳转到风险链接提示页。 ::: tip 什么是风险链接? Teek 把非本域名下的跳转链接视为风险链接。 ::: 如果您需要对一些链接放行或者专门拦截,请使用白名单和黑名单功能。 ```ts // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ riskLink: { enabled: true, whitelist: ["http://vp.teek.top", /https:\/\/github.com/], blacklist: [], }, }); ``` 白名单和黑名单支持字符串和正则表达式: * 当为字符串时,Teek 先完全匹配跳转的链接,如果匹配失败,则匹配跳转的链接开头部分(`startsWith` 方法),因此你可以配置某个域名或者某个完整的链接 * 当为正则表达式时,按照正则表达式进行匹配跳转的链接 当配置了黑名单,则只拦截黑名单的链接,其他链接全部放行,如果黑名单的链接在白名单里,则也会放行(白名单优先级最高)。 --- --- url: /10.配置/30.功能页配置.md --- # 功能页配置 Teek 支持构建分类页、标签页、归档页,文章清单页、登录页、风险链接提示页,这些页面本质上是一个 Markdown 文档,通过在 `frontmatter` 配置来开启功能,因此可以与其他文档一起放到任意目录下,并且和正常 Markdown 文档一样可以进行内容编写。 但是 Teek 建议放在 `@pages` 目录下,因为 Teek 不会对 `@pages` 目录下的文档做任何处理(自动生成侧边栏、站点分析,自动生成 `frontmatter` 等)。 ```sh . ├─ @pages │ ├── archivesPage.md │ ├── articleOverviewPage.md │ ├── categoriesPage.md │ ├── loginPage.md │ ├── riskLinkPage.md │ ├── tagsPage.md ``` ## 分类页 在 `frontmatter` 中配置 `categoriesPage: true` 和 `layout: home` 来开启分类页。 ```yaml --- title: 分类 permalink: /categories categoriesPage: true layout: home article: false --- ``` `permalink` 需要配置为 `/categories`,如果你希望修改为 `/c`,需要在主题配置中配置 `category.path` 为 `/c`: ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ category: { path: "/c", }, }); ``` ## 标签页 在 `frontmatter` 中配置 `tagsPage: true` 和 `layout: home` 来开启标签页。 ```yaml --- title: 标签 permalink: /tags tagsPage: true layout: home article: false --- ``` `permalink` 需要配置为 `/tags`,如果你希望修改为 `/t`,需要在主题配置中配置 `tag.path` 为 `/t`: ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ tag: { path: "/t", }, }); ``` ## 归档页 有两种方式可以开启归档页: 1. 在 `frontmatter` 配置 `archivesPage: true` 和 `layout: page` 来开启归档页 2. 在 `frontmatter` 配置 `layout: TkCataloguePage` 来开启归档页 ::: code-group ```yaml [方式 1] --- title: 归档 permalink: /archives archivesPage: true layout: page article: false sidebar: false --- ``` ```yaml [方式 2] --- title: 归档 permalink: /archives layout: TkCataloguePage article: false sidebar: false --- ``` ::: `permalink` 没有强制要求为 `/archives`,你可以根据自己的需求进行配置,然后在导航栏配置 `url` 为 `permalink` 的值即可。 通过 `frontmatter`,你可以定制归档页的部分文字:归档页所有可以配置的 `frontmatter` 如下: ```yaml --- title: 归档 permalink: /archives layout: TkCataloguePage totalCount: 总共 {count} 篇文章 year: 年 month: 月 count: 篇 notFound: 未指定 --- ``` 这些文字优先级会覆盖 Teek 的国际化文字。 ## 文章清单页 有两种方式可以开启文章清单页: 1. 在 `frontmatter` 配置 `articleOverviewPage: true` 和 `layout: page` 来开启文章清单页 2. 在 `frontmatter` 配置 `layout: TkArticleOverviewPage` 来开启文章清单页 ::: code-group ```yaml [方式 1] --- title: 归档 permalink: /articleOverview articleOverviewPage: true layout: page article: false sidebar: false --- ``` ```yaml [方式 2] --- title: 归档 permalink: /articleOverview layout: TkArticleOverviewPage article: false sidebar: false --- ``` ::: `permalink` 没有强制要求为 `/articleOverview`,你可以根据自己的需求进行配置,然后在导航栏配置 `url` 为 `permalink` 的值即可。 您可以通过 `publishDateFormat` 来设置发布时间的格式,比如 `yyyy-MM-dd`,默认为 `yyyy-MM-dd hh:mm:ss`。 ```yaml {6} --- title: 文章清单 permalink: /articleOverview articleOverviewPage: true layout: page publishDateFormat: yyyy-MM-dd article: false sidebar: false --- ``` ## 登录页 有两种方式可以开启登录页: 1. 在 `frontmatter` 配置 `loginPage: true` 和 `layout: false` 来开启登录页,此时登录页不含有导航 2. 在 `frontmatter` 配置 `layout: TkLoginPage` 来开启登录页,此时登录页顶部有导航 ::: code-group ```yaml [方式 1] --- permalink: /login layout: false loginPage: true logo: /teek-logo-large.png name: VitePress Theme Teek leftImg: /login/bg-1.png article: false --- ``` ```yaml [方式 2] --- permalink: /login layout: TkLoginPage logo: /teek-logo-large.png name: VitePress Theme Teek leftImg: /login/bg-1.png article: false --- ``` ::: `leftImg: /login/bg-1.png` 是添加左侧图片的配置项,如果添加该配置,左侧将会出现图片,右侧为登录框;如果不添加该配置,则登录框位于屏幕中间。 ## 风险链接提示页 有两种方式可以开启风险链接提示页: 1. 在 `frontmatter` 配置 `riskLinkPage: true` 和 `layout: false` 来开启登录页,此时风险链接提示页不含有导航 2. 在 `frontmatter` 配置 `layout: TkRiskLinkPage` 来开启登录页,此时风险链接提示页顶部有导航 ::: code-group ```yaml [方式 1] --- permalink: /risk-link layout: false riskLinkPage: true logo: /teek-logo-large.png name: VitePress Theme Teek # 与 desc 二选一 desc: 即将离开 VitePress Theme Teek,请注意财产安全 # 与 name 二选一 linkIllegal: 链接安全性校验中,请稍后 ... article: false --- ``` ```yaml [方式 2] --- permalink: /risk-link layout: TkRiskLinkPage logo: /teek-logo-large.png name: VitePress Theme Teek # 与 desc 二选一 desc: 即将离开 VitePress Theme Teek,请注意财产安全 # 与 name 二选一 linkIllegal: 链接安全性校验中,请稍后 ... article: false --- ``` ::: --- --- url: /10.配置/01.主题配置/20.卡片栏配置.md --- # 卡片栏配置 ## homeCardListPosition * 类型:`left` | `right` | `false` * 默认值:`right` 首页卡片栏列表位置,当为 `left` 则在文章列表左侧,当为 `right` 则在文章列表右侧,当为 `false` 时则不显示卡片栏。 ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ homeCardListPosition: "right", }); ``` ## homeCardSort * 类型:`("topArticle" | "category" | "tag" | "friendLink" | "docAnalysis")[]` * 默认值:`["topArticle", "category", "tag", "friendLink", "docAnalysis"]` 首页卡片的位置排序,当设置了 `homeCardSort` 但没有全部补全内容,Teek 会将剩余内容按照 `homeCardSort` 的顺序进行添加。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ homeCardSort: ["topArticle", "category", "tag", "friendLink", "docAnalysis"], }); ``` ```yaml [index.md] --- tk: homeCardSort: - topArticle - category - tag - friendLink - docAnalysis --- ``` ::: ## tagColor * 类型:`string[]` * 默认值: ```json [ { "border": "#bfdbfe", "bg": "#eff6ff", "text": "#2563eb" }, { "border": "#e9d5ff", "bg": "#faf5ff", "text": "#9333ea" }, { "border": "#fbcfe8", "bg": "#fdf2f8", "text": "#db2777" }, { "border": "#a7f3d0", "bg": "#ecfdf5", "text": "#059669" }, { "border": "#fde68a", "bg": "#fffbeb", "text": "#d97706" }, { "border": "#a5f3fc", "bg": "#ecfeff", "text": "#0891b2" }, { "border": "#c7d2fe", "bg": "#eef2ff", "text": "#4f46e5" } ] ``` 标签背景色,用于精选文章卡片的 `top + sticky` 功能和标签卡片的标签,背景色按顺序显示。 当在文章页的 `frontmatter` 配置时,如果颜色值有 `#` 号时请添加引号。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ tagColor: [ { border: "#bfdbfe", bg: "#eff6ff", text: "#2563eb" }, { border: "#e9d5ff", bg: "#faf5ff", text: "#9333ea" }, { border: "#fbcfe8", bg: "#fdf2f8", text: "#db2777" }, { border: "#a7f3d0", bg: "#ecfdf5", text: "#059669" }, { border: "#fde68a", bg: "#fffbeb", text: "#d97706" }, { border: "#a5f3fc", bg: "#ecfeff", text: "#0891b2" }, { border: "#c7d2fe", bg: "#eef2ff", text: "#4f46e5" }, ], }); ``` ```yaml [index.md] --- tk: tagColor: - border: "#bfdbfe" bg: "#eff6ff" text: "#2563eb" - border: "#e9d5ff" bg: "#faf5ff" text: "#9333ea" - border: "#fbcfe8" bg: "#fdf2f8" text: "#db2777" - border: "#a7f3d0" bg: "#ecfdf5" text: "#059669" - border: "#fde68a" bg: "#fffbeb" text: "#d97706" - border: "#a5f3fc" bg: "#ecfeff" text: "#0891b2" - border: "#c7d2fe" bg: "#eef2ff" text: "#4f46e5" --- ``` ::: ## blogger 博主信息,显示在首页左边第一个卡片。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ blogger: { name: "天客", // 博主昵称 slogan: "朝圣的使徒,正在走向编程的至高殿堂!", // 博主签名 avatar: "https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/user/avatar1.png", // 博主头像 shape: "circle-rotate", // 头像风格:square 为方形头像,circle 为圆形头像,circle-rotate 可支持鼠标悬停旋转,circle-rotate-last 将会持续旋转 59s circleBgImg: "/blog/bg4.webp", // 背景图片 circleBgMask: true, // 遮罩层是否显示,仅当 shape 为 circle 且 circleBgImg 配置时有效 circleSize: 100, // 头像大小 color: "#ffffff", // 字体颜色 // 状态,仅当 shape 为 circle 相关值时有效 status: { icon: "😪", // 状态图标 size: 24, // 图标大小 title: "困", // 鼠标悬停图标的提示语 }, }, }); ``` ```yaml [index.md] --- tk: blogger: name: 天客 slogan: 朝圣的使徒,正在走向编程的至高殿堂! avatar: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/user/avatar1.png shape: circle-rotate circleBgImg: /blog/bg4.webp circleBgMask: true circleSize: 100 color: #ffffff status: icon: "😪" size: 24 title: "困" --- ``` ```ts [更多配置项] import type { TkAvatarProps } from "@teek/components/common/Avatar"; interface Blogger { /** * 博主昵称 */ name: string; /** * 博主签名 */ slogan?: string; /** * 博主头像 */ avatar?: string; /** * 头像风格:square 为方形头像,circle 为圆形头像,circle-rotate 可支持鼠标悬停旋转,circle-rotate-last 将会持续旋转 59s * * @default 'square' */ shape?: TkAvatarProps["shape"] | "circle-rotate" | "circle-rotate-last"; /** * 背景图片地址,仅当 shape 为 circle 相关值时有效 * * @since v1.1.5 */ circleBgImg?: string; /** * 遮罩层是否显示,仅当 shape 为 circle 且 circleBgImg 配置时有效 * * @default true * @since v1.3.1 */ circleBgMask?: boolean; /** * 圆形头像大小,仅当 shape 为 circle 相关值时有效 * * @default 100 * @since v1.4.6 */ circleSize?: TkAvatarProps["size"]; /** * 字体颜色 * * @since v1.3.1 */ color?: string; /** * 状态,仅当 shape 为 circle 相关值时有效 * * @since v1.4.6 */ status?: { /** * 图标 */ icon: string; /** * 图标大小 * * @default 24 */ size?: TkAvatarProps["size"]; /** * 鼠标悬停图标的提示语 */ title?: string; }; } ``` ::: ## topArticle 精选文章卡片配置。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ topArticle: { enabled: true, // 是否启用精选文章卡片 title: "${icon}精选文章", // 卡片标题 emptyLabel: "暂无精选文章", // 精选文章为空时的标签 limit: 5, // 一页显示的数量 autoPage: false, // 是否自动翻页 pageSpeed: 4000, // 翻页间隔时间,单位:毫秒。autoPage 为 true 时生效 dateFormat: "yyyy-MM-dd hh:mm:ss", // 精选文章的日期格式 }, }); ``` ```yaml [index.md] --- tk: topArticle: enabled: true title: ${icon}精选文章 emptyLabel: 暂无精选文章 limit: 5 autoPage: false pageSpeed: 4000 dateFormat: yyyy-MM-dd hh:mm:ss --- ``` ```ts [更多配置项] import type { VpRouter } from "@teek/composables"; interface TopArticle { /** * 是否启用精选文章卡片 * * @default true */ enabled?: boolean; /** * 卡片标题 * * @default '${icon}精选文章' */ title?: string | ((icon: string) => string); /** * 精选文章为空时的标签 * * @default '暂无精选文章' */ emptyLabel?: string; /** * 一页显示的数量 * * @default 5 */ limit?: number; /** * 是否自动翻页 * * @default false */ autoPage?: boolean; /** * 翻页间隔时间,单位:毫秒。autoPage 为 true 时生效 * * @default 4000 (4秒) */ pageSpeed?: number; /** * 精选文章的日期格式 * * @default 'yyyy-MM-dd hh:mm:ss' */ dateFormat?: "yyyy-MM-dd" | "yyyy-MM-dd hh:mm:ss" | ((date: number | string) => string); /** * 是否使用 UTC 时间 * * @default true */ dateUTC?: boolean; /** * 点击标题时触发,可以通过 router.go 跳转到其他页面,也可以通过 window.open 打开新窗口 * * @since v1.1.2 */ titleClick?: (router: VpRouter) => void; } ``` ::: ## category 分类卡片配置。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ category: { enabled: true, // 是否启用分类卡片 path: "/categories", // 分类页访问地址 pageTitle: "${icon}全部分类", // 分类页卡片标题 homeTitle: "${icon}文章分类", // 卡片标题 moreLabel: "更多 ...", // 查看更多分类标签 emptyLabel: "暂无文章分类", // 分类为空时的标签 limit: 5, // 一页显示的数量 autoPage: false, // 是否自动翻页 pageSpeed: 4000, // 翻页间隔时间,单位:毫秒。autoPage 为 true 时生效 }, }); ``` ```yaml [index.md] --- tk: category: enabled: true path: /categories pageTitle: ${icon}全部分类 homeTitle: ${icon}文章分类 moreLabel: 更多 ... emptyLabel: 暂无文章分类 limit: 5 autoPage: false pageSpeed: 4000 --- ``` ```ts [更多配置项] interface Category { /** * 是否启用分类卡片 * * @default true */ enabled?: boolean; /** * 分类页访问地址 * * @default '/categories' */ path?: string; /** * 分类页卡片标题 * * @default '${icon}全部分类' */ pageTitle?: string | ((icon: string) => string); /** * 卡片标题 * * @default '${icon}文章分类' */ homeTitle?: string | ((icon: string) => string); /** * 查看更多分类标签 * * @default '更多 ...' */ moreLabel?: string; /** * 分类为空时的标签 * * @default '暂无文章分类' */ emptyLabel?: string; /** * 一页显示的数量 * * @default 5 */ limit?: number; /** * 是否自动翻页 * * @default false */ autoPage?: boolean; /** * 翻页间隔时间,单位:毫秒。autoPage 为 true 时生效 * * @default 4000 (4秒) */ pageSpeed?: number; } ``` ::: ## tag 标签卡片配置。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ tag: { enabled: true, // 是否启用标签卡片 path: "/tags", // 标签页访问地址 pageTitle: "${icon}全部标签", // 标签页页卡片标题 homeTitle: "${icon}热门标签", // 卡片标题 moreLabel: "更多 ...", // 查看更多分类标签 emptyLabel: "暂无标签", // 标签为空时的标签 limit: 21, // 一页显示的数量 autoPage: false, // 是否自动翻页 pageSpeed: 4000, // 翻页间隔时间,单位:毫秒。autoPage 为 true 时生效 }, }); ``` ```yaml [index.md] --- tk: tag: enabled: true path: /tags pageTitle: ${icon}全部标签 homeTitle: ${icon}热门标签 moreLabel: 更多 ... emptyLabel: 暂无标签 limit: 5 autoPage: false pageSpeed: 4000 --- ``` ```ts [更多配置项] interface Tag { /** * 是否启用标签卡片 * * @default true */ enabled?: boolean; /** * 标签页访问地址 * * @default '/tags' */ path?: string; /** * 标签页页卡片标题 * * @default '${icon}全部标签' */ pageTitle?: string | ((icon: string) => string); /** * 卡片标题 * * @default '${icon}热门标签' */ homeTitle?: string | ((icon: string) => string); /** * 查看更多分类标签 * * @default '更多 ...' */ moreLabel?: string; /** * 标签为空时的标签 * * @default '暂无标签' */ emptyLabel?: string; /** * 一页显示的数量 * * @default 21 */ limit?: number; /** * 是否自动翻页 * * @default false */ autoPage?: boolean; /** * 翻页间隔时间,单位:毫秒。autoPage 为 true 时生效 * * @default 4000 (4秒) */ pageSpeed?: number; } ``` ::: ## friendLink 友情链接卡片配置。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ friendLink: { enabled: true, // 是否启用友情链接卡片 list: [ { name: "Teeker", desc: "朝圣的使徒,正在走向编程的至高殿堂!", avatar: "https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/user/avatar2.png", link: "http://notes.teek.top/", }, { name: "Teeker Design Vue3", desc: "一个颜值强大、功能丰富、开箱即用的中后台管理系统解决方案", avatar: "https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/teek-design/20250807012638.png", link: "https://vue3-design-docs.teek.top/", }, ], // 友情链接数据列表 title: "${icon}友情链接", // 卡片标题 emptyLabel: "暂无友情链接", // 友情链接为空时的标签 limit: 5, // 一页显示的数量 autoScroll: false, // 是否自动滚动 scrollSpeed: 2500, // 滚动间隔时间,单位:毫秒。autoScroll 为 true 时生效 autoPage: false, // 是否自动翻页 pageSpeed: 4000, // 翻页间隔时间,单位:毫秒。autoPage 为 true 时生效 }, }); ``` ```yaml [index.md] --- tk: friendLink: enabled: true list: - name: Teeker desc: 朝圣的使徒,正在走向编程的至高殿堂! avatar: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/user/avatar2.png link: http://notes.teek.top/ - name: Teeker Design Vue3 desc: 一个颜值强大、功能丰富、开箱即用的中后台管理系统解决方案 avatar: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/teek-design/20250807012638.png link: https://vue3-design-docs.teek.top/ title: ${icon}友情链接 emptyLabel: 暂无友情链接 limit: 5 autoScroll: false scrollSpeed: 2500 autoPage: false pageSpeed: 4000 --- ``` ```ts [更多配置项] import type { VpRouter } from "vitepress-theme-teek"; interface FriendLink { /** * 是否启用友情链接卡片 * * @default true */ enabled?: boolean; /** * 友情链接数据列表 */ list?: { /** * 友链名称 */ name: string; /** * 友链头像 */ avatar?: string; /** * 友链描述 */ desc?: string; /** * 友链链接 */ link?: string; /** * img 标签的 alt * * @default name */ alt?: string; }[]; /** * 卡片标题 * * @default '${icon}友情链接' */ title?: string | ((icon: string) => string); /** * 友情链接为空时的标签 * * @default '暂无友情链接' */ emptyLabel?: string; /** * 一页显示的数量 * * @default 5 */ limit?: number; /** * 是否自动滚动 * * @default false */ autoScroll?: boolean; /** * 滚动间隔时间,单位:毫秒。autoScroll 为 true 时生效 * * @default 2500 (2.5秒) */ scrollSpeed?: number; /** * 是否自动翻页 * * @default false */ autoPage?: boolean; /** * 翻页间隔时间,单位:毫秒。autoPage 为 true 时生效 * * @default 4000 (4秒) */ pageSpeed?: number; /** * 点击标题时触发,可以通过 router.go 跳转到其他页面,也可以通过 window.open 打开新窗口 * * @since v1.1.2 */ titleClick?: (router: VpRouter) => void; } ``` ::: ## docAnalysis 站点信息卡片配置。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ docAnalysis: { enabled: true, // 是否启用站点信息卡片 createTime: "2021-10-19", // 站点创建时间 wordCount: true, // 是否开启文章页的字数统计 readingTime: true, // 是否开启文章页的阅读时长统计 // 访问量、访客数统计配置 statistics: { provider: "busuanzi", // 网站流量统计提供商 siteView: true, // 是否开启首页的访问量和排名统计 pageView: true, // 是否开启文章页的浏览量统计 tryRequest: false, // 如果请求网站流量统计接口失败,是否重试 tryCount: 5, // 重试次数,仅当 tryRequest 为 true 时有效 tryIterationTime: 2000, // 重试间隔时间,单位:毫秒,仅当 tryRequest 为 true 时有效 permalink: true, // 是否只统计永久链接的浏览量,如果为 false,则统计 VitePress 默认的文档目录链接 }, // 自定义现有信息 overrideInfo: [ { key: "lastActiveTime", label: "活跃时间", value: (_, currentValue) => (currentValue + "").replace("前", ""), show: true, }, ], // 自定义额外信息 appendInfo: [{ key: "index", label: "序号", value: "天客 99" }], }, }); ``` ```yaml [index.md] --- tk: docAnalysis: enabled: true createTime: 2021-10-19 wordCount: true readingTime: true statistics: provider: "busuanzi" siteView: true pageView: true appendInfo: - key: "index" label: "序号" value: "天客 99" --- ``` ```ts [更多配置项] interface DocAnalysis { /** * 是否启用站点信息卡片 * * @default true */ enabled?: boolean; /** * 卡片标题 * * @default '${icon}站点信息' */ title?: string | ((icon: string) => string); /** * 项目创建时间 */ createTime?: string; /** * 是否开启文章页的字数统计 * * @default true */ wordCount?: boolean; /** * 是否开启文章页的阅读时长统计 * * @default true */ readingTime?: boolean; /** * 访问量、访客数统计配置 */ statistics?: { /** * 自建网站流量统计的 URL,支持的 URL 格式与提供商 provider 绑定 */ url?: string; /** * 网站流量统计提供商 */ provider?: "" | "busuanzi" | "vercount"; /** * 是否开启首页的访问量和排名统计 * * @default true */ siteView?: boolean; /** * 是否开启文章页的浏览量统计 * * @default true */ pageView?: boolean; /** * 如果请求网站流量统计接口失败,是否重试,类型 boolean * * @default false */ tryRequest?: boolean; /** * 重试次数,仅当 tryRequest 为 true 时有效 * * @default 5 */ tryCount?: number; /** * 重试间隔时间,单位毫秒,仅当 tryRequest 为 true 时有效 * * @default 2000 */ tryIterationTime?: number; /** * 是否只统计永久链接的浏览量,如果为 false,则统计 VitePress 默认的文档目录链接 * * @default true */ permalink?: boolean; /** * 自定义请求函数,返回 UvPvData 数据 * * @param url 统计接口地址 * @param createScriptFn 创建一个 script 标签的函数 */ requestFn?: (url: string | undefined, createScriptFn: typeof createScript) => UvPvData | Promise; }; /** * 自定义现有信息 * originValue 为计算前的数据,currentValue 为计算后的数据(加单位的数据),针对 lastActiveTime 这些需要判断 N 分、N 时、N 天的 key,originValue 为具体的时间,需要自行计算 */ overrideInfo?: (Omit, "value"> & { value?: (originValue: string | number, currentValue?: string | number) => string; })[]; /** * 自定义额外信息,类型和 overrideInfo 一样 * @default [] */ appendInfo?: | (Omit & { key: string })[] | (() => (Omit & { key: string })[]); } interface DocAnalysisInfo { /** * 站点信息唯一标识 */ key: | "totalPosts" | "weekAddNum" | "monthAddNum" | "runtime" | "totalWordCount" | "lastActiveTime" | "viewCount" | "visitCount" | string; /** * 站点信息标签 */ label: string; /** * 站点信息值的描述 */ value: string; /** * 是否显示在站点信息 * * @default true */ show?: boolean; } ``` ::: ::: tip 如果想开启访问量、访客数统计,请使用 `statistics.provider` 选择网站流量统计提供商。 ::: 当想修改站点信息内置的信息时,可以使用 `overrideInfo` 配置项,该配置项是一个数组对象,对象的 `key` 为信息标识,`value` 是一个函数,接收两个参数 `originValue` 和 `currentValue`: * originValue:站点信息卡片的原始值,如创建时间为 2021-10-19 * currentValue:站点信息卡片当前渲染的值,如创建时间渲染的值为 N 天前 比如想将 `文章数目` 改为 `文章总数目`: ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ docAnalysis: { overrideInfo: [{ key: "totalPosts", label: "文章总数目" }], }, }); ``` 比如想隐藏最后活动时间: ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ docAnalysis: { overrideInfo: [{ key: "lastActiveTime", show: false }], }, }); ``` key 可选值如下: * `totalPosts`:文章总数 * `weekAddNum`:近一周新增 * `monthAddNum`:近一月新增 * `runtime`:已运行时间 * `totalWordCount`:本站总字数 * `lastActiveTime`:最后活动时间 * `viewCount`:本站被访问了 * `visitCount`:本站曾来访过 **获取网站访问量数据** 如果你想要获取网站访问量数据,可以通过监听 Teek 触发的事件获取: ```ts window.addEventListener("views", (event: any) => { console.log("网站访问量数据", event.detail); }); ``` 利用这个事件,你可以在站点信息卡片配置利用 `appendInfo` 来配置更多的访问量信息: ```vue ``` --- --- url: /01.指南/10.使用/25.国际化.md --- # 国际化 Teek 默认使用中文,如果你希望使用其他语言,你可以参考下面的方案。 ## 全局语言配置 在 `Teek.Layout` 组件传入 `locale` 参数,即可设置默认语言。 ```ts // .vitepress/config.mts import Teek, { en } from "vitepress-theme-teek"; import "vitepress-theme-teek/index.css"; export default { extends: Teek, Layout: h(Teek.Layout, { locale: en }), }; ``` 如果希望根据 VitePress 的国际化动态切换语言,可以定义一个组件 `TeekLayoutProvider.vue`。 ```vue [TeekLayoutProvider.vue] ``` 然后在 `.vitepress/theme/index.ts` 中传入 `TeekLayoutProvider` 组件。 ```ts // .vitepress/theme/index.ts import Teek, { en } from "vitepress-theme-teek"; import "vitepress-theme-teek/index.css"; import TeekLayoutProvider from "../components/TeekLayoutProvider.vue"; export default { extends: Teek, Layout: TeekLayoutProvider, }; ``` `lang` 是 VitePress 国际化的一个配置项: ```ts import { defineConfig } from "vitepress"; export default defineConfig({ locales: { root: { lang: "zh-CN" }, en: { lang: "en" }, }, }); ``` ### 语言列表 Teek 目前支持以下语言: * 简体中文(zh-cn) * English(en) ### 自定义语言 如果你需要使用其他的语言,可以添加一个语言配置文件。 比如需要添加繁体中文(zh-tw)语言,步骤如下: 1. 创建 `.vitepress/theme/locale/zh-tw.ts` 文件(路径位置任意) 2. 然后参考 Teek 现有的任一 [语言文件](https://github.com/Kele-Bingtang/vitepress-theme-teek/tree/master/vitepress-theme-teek/src/locale/lang),将里面的内容拷贝到 `zh-tw.ts` 文件中,并将所有内容(Value)修改为 `zh-tw` 语言 3. 最后通过 `locale` 属性传入到 `Teek.Layout` 组件中 ```vue [TeekLayoutProvider.vue] {4,10} ``` ### provide 方式 除了通过 `locale` 属性传入语言配置,Teek 也支持通过 `provide` 方式传入语言配置: ```vue {5-8} ``` ## 国际化下配置文件 ### VitePress 配置 假设国际化环境下,配置文件目录如下: ```sh .vitepress ├─ locales │ ├─ zh.ts # 中文配置 │ ├─ shared.ts # 共享配置 │ ├─ en.ts # 英文配置 │ ├─ xx.ts # 其他语言配置 ├─ config.mts ``` `.vitepress/config.mts` 内容如下: ```ts // .vitepress/config.mts import { defineConfig } from "vitepress"; import shared from "./locales/shared"; import zh from "./locales/zh"; import en from "./locales/en"; export default defineConfig({ ...shared, locales: { root: { label: "简体中文", ...zh }, en: { label: "English", ...en }, }, }); ``` VitePress 默认会对 `shared.ts` 和当前语言的配置文件进行合并,且配置同名时,以当前语言配置为主,如 `zh.ts` 和 `en.ts` 会覆盖 `shared.ts` 中的同名配置。 利用这个机制,你可以在 `shared.ts` 中定义一些通用的配置,然后 `zh.ts` 和 `en.ts` 里配置不同语言的配置,如: ::: code-group ```ts [shared.ts] import { defineConfig } from "vitepress"; export default defineConfig({ title: "Hd Security", cleanUrls: false, lastUpdated: true, head: [ ["link", { rel: "icon", type: "image/svg+xml", href: "/teek-logo-mini.svg" }], ["link", { rel: "icon", type: "image/png", href: "/teek-logo-mini.png" }], ["meta", { property: "og:type", content: "website" }], ["meta", { property: "og:locale", content: "zh-CN" }], ["meta", { property: "og:title", content: "Teek | VitePress Theme" }], ["meta", { name: "author", content: "Teek" }], ["link", { rel: "icon", href: "/favicon.ico", type: "image/png" }], ["link", { rel: "stylesheet", href: "//at.alicdn.com/t/font_2989306_w303erbip9.css" }], // 阿里在线矢量库 ], markdown: { lineNumbers: true, }, // https://vitepress.dev/reference/default-theme-config themeConfig: { logo: "https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/user/avatar1.png", search: { provider: "local", }, }, }); ``` ```ts [zh.ts] import { defineConfig } from "vitepress"; const description = ["Teek 使用文档", "VitePress 主题"].toString(); export default defineConfig({ lang: "zh-CN", description: description, head: [ ["meta", { name: "description", description }], ["meta", { name: "keywords", description }], ], markdown: { container: { tipLabel: "提示", warningLabel: "警告", dangerLabel: "危险", infoLabel: "信息", detailsLabel: "详细信息", }, }, themeConfig: { darkModeSwitchLabel: "主题", sidebarMenuLabel: "菜单", returnToTopLabel: "返回顶部", lastUpdatedText: "上次更新时间", outline: { level: [2, 4], label: "本页导航", }, docFooter: { prev: "上一页", next: "下一页", }, nav: [ { text: "首页", link: "/" }, { text: "指南", link: "/guide/intro" }, { text: "配置", link: "/reference/config" }, { text: "开发", link: "/develop/intro" }, { text: "归档", link: "/archives" }, ], editLink: { text: "在 GitHub 上编辑此页", pattern: "https://github.com/Kele-Bingtang/vitepress-theme-teek/edit/master/docs/:path", }, }, }); ``` ```ts [en.ts] import { defineConfig } from "vitepress"; const description = ["Teek Documentation", "VitePress Theme"].toString(); export default defineConfig({ lang: "en-US", description: description, head: [ ["meta", { name: "description", description }], ["meta", { name: "keywords", description }], ], markdown: { container: { tipLabel: "Tip", warningLabel: "Warning", dangerLabel: "Danger", infoLabel: "Info", detailsLabel: "Details", }, }, themeConfig: { ...teekConfig.themeConfig, darkModeSwitchLabel: "Theme", sidebarMenuLabel: "Menu", returnToTopLabel: "To Top", lastUpdatedText: "LastUpdated", outline: { level: [2, 4], label: "Page Navigation", }, docFooter: { prev: "prev", next: "next", }, nav: [ { text: "index", link: "/en" }, { text: "guide", link: "/guide/intro" }, { text: "reference", link: "/reference/config" }, { text: "develop", link: "/develop/intro" }, { text: "archives", link: "/en/archives" }, ], editLink: { text: "Edit this page on GitHub", pattern: "https://github.com/Kele-Bingtang/vitepress-theme-teek/edit/master/docs/:path", }, }, }); ``` ::: ### Teek 配置 在非国际化配置文件里下,您可以直接在 VitePress 的配置里使用 `extends` 来继承 Teek 的配置,但是在国际化配置文件下,`extends` 配置会失效。 因此需要将 Teek 配置的 `themeConfig` 手动添加到 VitePress 的 `themeConfig` 里。 ::: code-group ```ts [shared.ts] import { defineConfig } from "vitepress"; import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ // 公共配置 ... }); export default defineConfig({ extends: teekConfig, // ... }); ``` ```ts [zh.ts] import { defineConfig } from "vitepress"; import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ // zh 配置下配置 ... }); export default defineConfig({ themeConfig: { ...teekConfig.themeConfig, // ... }, }); ``` ```ts [en.ts] import { defineConfig } from "vitepress"; import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ // en 环境下配置 ... }); export default defineConfig({ themeConfig: { ...teekConfig.themeConfig, // ... }, }); ``` ::: 举个例子,您可以在中文和英文环境下分别取不同的名字: ::: code-group ```ts [zh.ts] import { defineConfig } from "vitepress"; import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ blogger: { name: "天客", slogan: "朝圣的使徒,正在走向编程的至高殿堂!", }, }); export default defineConfig({ themeConfig: { ...teekConfig.themeConfig, // ... }, }); ``` ```ts [en.ts] import { defineConfig } from "vitepress"; import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ blogger: { name: "Teeker", slogan: "Code Pilgrims march to the summit of code mastery!", }, }); export default defineConfig({ themeConfig: { ...teekConfig.themeConfig, // ... }, }); ``` ::: ## 给 root 语言添加目录 这里对一个特殊场景进行说明。 VitePress 支持的国际化文档目录如下: ```sh docs/ ├─ es/ │ ├─ foo.md ├─ fr/ │ ├─ foo.md ├─ foo.md ``` 根目录下的 `foo.md` 是 root 语言(默认语言)的文档,当 Markdown 文件多起来时,根目录下文件显得很拥挤,那么可以将这些文档放到一个目录下,假设默认语言是 `zh`,则: ```sh docs/ ├─ es/ │ ├─ foo.md ├─ fr/ │ ├─ foo.md ├─ zh/ │ ├─ foo.md ``` 但是 VitePress 无法感知到 root 语言(默认语言)的文档已经放到 `zh` 目录下,它依然只扫描根目录的 Markdown 文件作为默认语言的文档,因此需要使用 VitePress 提供的 `rewrites` 进行重定向,同时 Teek 也无法感知文档进行了移动,因此需要配置 `vitePlugins.sidebarOption.localeRootDir` ```ts {6-10,15-17} import { defineConfig } from "vitepress"; import { defineTeekConfig } from "vitepress-theme-teek/config"; // Teek 主题配置 const teekConfig = defineTeekConfig({ vitePlugins: { sidebarOption: { localeRootDir: "zh", }, }, }); // VitePress 配置 export default defineConfig({ rewrites: { "zh/:rest*": ":rest*", }, }); ``` --- --- url: /01.指南/10.使用/40.图标使用.md --- # 图标使用 Teek 默认注册了全局组件 `TkIcon`,因此你可以通过该组件快捷引入图标。 `TkIcon` 默认支持如下类型的图标: * svg * unicode * iconfont * symbol * img * component * iconifyOffline * iconifyOnline 除此之外,您可以通过默认插槽传入自定义图标组件。 `TkIcon` 组件的基础使用以及 API 介绍请看 [Icon 图标](/ecosystem/components/icon)。 ::: tip Teek 所有的 Icon 图标相关配置项,都使用 `TkIcon` 组件,因此怎么使用 `TkIcon` 的 `icon` 属性,就怎么使用图标相关配置项。 ::: ## SVG 图标 您可以下载一个 `svg` 图标到项目里,然后传入 `TkIcon` 组件中。 在 Markdown 文档有两种格式输入: ::: code-group ```vue [props 方式] ``` ```html [插槽方式] ``` ::: 输出: SVG 图标在哪里获取?您可以访问 [阿里巴巴矢量图标库](https://www.iconfont.cn/),然后搜索需要的图标,最后在下载时选择 **复制 SVG 图标**。 除此之外,您也可以可以在该网站上下载 `Unicode`、`Font Class`、`Symbol` 图标,然后传入 `TkIcon` 组件中。 如: ```html ``` ## Iconify 图标 ### 在线图标 如果您的项目部署在互联网上,那么可以使用 `Iconify` 的在线图标,只需要往 `TkIcon` 组件传入在线图标名称即可。 在 Markdown 文档输入: ```html ``` 输出: 其中 `mdi:github` 为在线图标名,更多的在线图标请访问:[Iconify 在线图标](https://icon-sets.iconify.design/)。 > 如果项目部署在内网,或担心网络访问速度慢导致无法加载图标怎么办?往下看。 ### 离线 JSON 图标 您可以直接将 `Iconify` 图标以 JSON 方式注册到本地,然后引入到 `TkIcon` 组件里,如: ```sh pnpm add @iconify-json/ant-design -d ``` 然后在 `.vitepress/theme/index.ts` 里注册到 Teek 里: ```ts import { addIcons } from "vitepress-theme-teek"; import icons from "@iconify-json/ant-design/icons.json"; addIcons(icons); ``` 最后和在线方式一样使用 `TkIcon` 组件: ```html ``` `TkIcon` 优先从已注册的图标名里获取,当获取不到时就会从互联网上下载。 这里演示安装了 `ant design` 的图标,其他的图标集合根据需要安装。 `Iconify` JSON 图标的依赖名约定是 `@iconify-json/{name}`,引入 JSON 图标数据的路径约定是 `@iconify-json/{name}/icons.json`。 ### 离线 Icon 图标 您可以直接将 `Iconify` 的图标集合安装到本地,然后引入到 `TkIcon` 组件里,如: ```sh pnpm add @iconify-icons/ant-design -d ``` 然后使用: ```vue ``` 这里演示安装了 `ant design` 的图标,其他的图标集合根据需要安装。 `Iconify` Icon 图标的依赖名约定是 `@iconify-icons/{name}` 或者 `@iconify/icons-{name}`。 ### 两个离线图标方式对比 * JSON 图标方式需要在项目初始化时注册进去,后续直接通过字符串引用 * Icon 图标方式在每次使用时需要手动引入 ::: info `TkIcon` 并没有实现 `Iconify` 相关逻辑,而是通过代理 `Iconify` 的 API 实现。 ::: ## 内置图标 ### SVG 图标 下面展示 Teek 内置的主题图标集合,Teek 只保留了自身引用的图标,您可以在页面上随处可见,如果您需要额外的图标,请参考上面的方式添加。 当点击图标后将会复制引用图标代码(参考下面高亮部分)到您的剪切板中,然后就可以粘贴到代码中: ```vue {2} ``` ### 社交图标(iconfont) 如下是 Teek 内置的社交图标集合,可以在导航栏、侧边栏、社交配置 `social` 里快速应用。 如在社交配置 `social` 中添加社交图标: ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; export const teekConfig = defineTeekConfig({ social: [ { icon: "icon-github", // iconfont 图标名 name: "GitHub", link: "https://github.com/kele-bingtang", }, { icon: "icon-gitee", // iconfont 图标名 name: "Gitee", link: "https://gitee.com/kele-bingtang", }, ], }); ``` 如果 Teek 提供的社交图标不满足您的要求,您可以使用访问 [阿里巴巴矢量图标库](https://www.iconfont.cn/) 来下载您需要的任何图标。 --- --- url: /15.主题开发/60.容器自定义.md --- # 容器自定义 Teek 提供了两种创建容器的 API,这两种容器 Teek 分别命名为 Simple 容器、Card 容器。 Teek 容器都有哪些?请看 [Markdown 拓展](/guide/markdown)。 容器 API 请看 [Markdown 插件工具](/ecosystem/md-plugin-utils) ## Simple 容器 VitePress 的 `info`、`tip`、`warning`、`danger` 容器都是 Simple 容器,其原理是添加 `div` 来包裹 Markdown 文本,然后通过 CSS 来实现样式。 举个例子(并非实际) ```markdown ::: tip 提示 测试 TIP ::: ``` 最终渲染为: ```html

提示

测试 TIP

``` 此时就可以在 CSS 文件中通过 `.tip` 和 `.title` 来添加样式,如添加一个背景色,给 title 加大字号等。 Teek 的 Simple 容器 API 请看 [simpleContainer.ts](https://github.com/Kele-Bingtang/vitepress-theme-teek/blob/master/packages/markdown/helper/simpleContainer.ts) 文件,该文件参考自 VitePress 官方项目,并修改了些许内容。 `simpleContainer.ts` 文件中真正干活的 API 为 `createContainerThenGet` 函数,该函数提供两个 HTML 模板: ::: code-group ```html [开启标题]

${defaultTitle || 传入标题}

${输入的内容}

${输入的内容}

demo1

测试 demo1 容器

容器标题

测试 demo1 容器

测试 demo2 容器

指南", link: "http://vp.teek.top/", }, ], }, }); ``` ```ts {7-12} [图片方式] import { defineConfig } from "vitepress"; export default defineConfig({ themeConfig: { nav: [ { text: `
指南
`, link: "http://vp.teek.top/", }, ], }, }); ``` ::: Teek 内置的 `iconfont` 仅仅是 [社交图标](/guide/icon-use.html#社交图标-iconfont),更多 `iconfont` 图标可以去 [阿里巴巴矢量图标库](https://www.iconfont.cn/) 下载。 举个例子: 假设您已经下载了一组 `iconfont` 图标,其目录结构应该如下: ```sh . ├─ iconfont.css ├─ iconfont.js ├─ iconfont.json ├─ iconfont.ttf ├─ iconfont.woff ├─ iconfont.woff2 ``` 将该目录放到 `.vitepress/theme/assert/iconfont` 下(实际按照自己的路径存放),然后在 `.vitepress/theme/index.ts` 文件里引入: ```ts import "./assets/iconfont/system/iconfont.js"; import "./assets/iconfont/system/iconfont.css"; ``` 接下来在通过 `` 在导航栏、侧边栏等位置使用图标。 ::: tip 添加样式 1. 使用内联样式 `` 2. 自定义一个 `class`,然后编写样式 ::: ### 组件方式 ::: warning 组件方式不能作用在父级导航上。 ::: 上面的方法需要传入一个 HTML 标签来实现,如果有很多导航配置,那么写起来很麻烦,且可读性较差, 在 `.vitepress/theme/components` 自定义一个组件 `NavIcon.vue` 来进行封装: ```vue ``` 然后在 `.vitepress/theme/index.ts` 里全局注册 ```ts // .vitepress/theme/index.ts import Teek from "vitepress-theme-teek"; import "vitepress-theme-teek/index.css"; import NavIcon from "./components/NavIcon.vue"; export default { extends: Teek, Layout: Teek.Layout, enhanceApp({ app }) { app.component("NavIcon", NavIcon); }, }; ``` 最后在 `themeConfig.nav` 使用: ```ts {7-17} import { defineConfig } from "vitepress"; export default defineConfig({ themeConfig: { nav: [ { component: "NavIcon", props: { text: "指南", link: "/guide/intro", activeMatch: "/01.指南/", iconProps: { icon: "https://vp.teek.top/teek-logo-mini.svg", iconType: "img", }, }, }, { text: "资源", items: [ { component: "NavIcon", props: { text: "案例", link: "/case", subMenu: true, iconProps: { icon: "https://vp.teek.top/teek-logo-mini.svg", iconType: "img", size: 12, // 大小 }, }, }, { component: "NavIcon", props: { text: "常见问题", link: "/theme/qa", subMenu: true, iconProps: { icon: "https://vp.teek.top/teek-logo-mini.svg", iconType: "img", }, }, }, ], }, ], }, }); ``` * `NavIcon` 组件的 `props` 里的配置项和 `VitePress` 的 `nav` 配置项一致 * `iconProps` 是 `TkIcon` 组件的 `props`,更多具体 API 用法请参考 [TkIcon](/ecosystem/components/icon) 组件 --- --- url: /20.资源/01.常见问题.md --- # 常见问题 ## 安装第三方 Markdown 插件后,Teek 内置插件失效 请不要使用 VitePress 提供的 `markdown.config` 函数来加载 `Markdown-it` 插件,因为 VitePress 方式会覆盖主题内置的 `Markdown-it` 插件。 请在 `teekConfig` 中使用 `markdown.plugins` 函数来加载 `Markdown-it` 插件。 ::: code-group ```ts [正确用法] {6-10} // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; import myMdPlugin from "my-md-plugin"; const teekConfig = defineTeekConfig({ markdown: { config: md => { md.use(myMdPlugin); }, }, }); ``` ```ts [错误用法] {6-10} // .vitepress/config.mts import { defineConfig } from "vitepress"; import myMdPlugin from "my-md-plugin"; export default defineConfig({ markdown: { config: md => { md.use(myMdPlugin); }, }, }); ``` ::: 举个例子,要想引入 [vitepress-plugin-legend](https://github.com/flingyp/vitepress-plugin-legend/blob/main/README.zh-CN.md) 插件来显示 mermaid 代码块,就需要在 teekConfig 中加载,而不是在 defineConfig 中加载。 ## 侧边栏问题 ### 侧边栏新增图标 请参阅文档 [侧边栏新增图标](/guide/plugins.html#侧边栏新增图标)。 ### 侧边栏支持折叠 进行如下配置: ```ts const teekConfig = defineTeekConfig({ vitePlugins: { sidebarOption: { collapsed: true, // 开启侧边栏折叠功能。true 默认折叠,false 默认不折叠 }, }, }); ``` --- --- url: /15.主题开发/01.开发思路.md --- # 开发思路 ::: note 摘要 只要会编写 `Vue` 组件,那么就可以发挥您天马行空的想象力,来构建自己的主题。 ::: right 2025-03-17 @Teek ::: 本系列为 **主题开发**,主要介绍 Teek 的开发思路,当然这只是提供思路,不会细到每一个文件的逻辑讲解。 在阅读完本系列内容后,您可以去阅读 Teek 的源码,了解 Teek 的实现思路,也许对您的主题开发之路有些帮助。 基于 VitePress 开发一个主题是非常简单的,在 [自定义主题](https://vitepress.dev/zh/guide/custom-theme) 和 [拓展默认主题](https://vitepress.dev/zh/guide/extending-default-theme) 已经详细的介绍了如何开发一个主题。 ## Layout 函数 VitePress 默认内置了一套主题,如果觉得内置主题的功能不满足需求或者想额外添加一些功能,可以编写组件来替换/拓展 VitePress 主题。 首先 VitePress **必须** 需要接收一个 `Layout` 函数,该函数需要返回一个 `vue` 组件作为 **入口组件**: ```ts {5} import DefaultTheme from "vitepress/theme"; export default { extends: DefaultTheme, Layout: /* Vue 组件 */, enhanceApp({ app, router, siteData }) {}, }; ``` 在 `Layout` 实现一个组件主要有 2 种方式: 1. `h` 函数 + `.vue` 组件 ```ts {7} import DefaultTheme from "vitepress/theme"; import MyComponent from "./MyComponent.vue"; import { h } from "vue"; export default { extends: DefaultTheme, Layout: () => h(MyComponent), enhanceApp({ app, router, siteData }) {}, }; ``` 2. `defineComponent` 函数生成 `vue` 组件 ```ts {7-14} import DefaultTheme from "vitepress/theme"; import MyComponent from "./MyComponent.vue"; import { h } from "vue"; export default { extends: DefaultTheme, Layout: defineComponent({ name: "ConfigProvider", setup(_, { slots }) { // 自定义一些全局逻辑 return () => h(MyComponent, null, slots); }, }), enhanceApp({ app, router, siteData }) {}, }; ``` 可以看到,`defineComponent` 函数的返回值还是使用了 `h` 函数 + `.vue` 组件,但是这样好处在于可以添加一些全局逻辑或往所有组件里注入常用数据,因为这是在所有组件加载前执行的逻辑。 比如 Teek 注入了文章信息数据、并开启一些监听器(随着迭代,下方代码不一定是最新的): ```ts {9-16} import DefaultTheme from "vitepress/theme"; import MyComponent from "./MyComponent.vue"; import { h, type Component } from "vue"; const configProvider = (Layout: Component) => { return defineComponent({ name: "ConfigProvider", setup(_, { slots }) { const { theme } = useData(); // 往主题注入数据 provide(postsContext, theme.value.posts); // 开启监听器 usePermalink().startWatch(); useAnchorScroll().startWatch(); useViewTransition(); return () => h(Layout, null, slots); }, }); }; export default { extends: DefaultTheme, Layout: configProvider(MyComponent), enhanceApp({ app, router, siteData }) {}, }; ``` 相比较直接用 `h` 函数来构建组件,`defineComponent` 函数更灵活,多了一个中间层方便实现一些逻辑。 ## 入口组件 阅读内容前,您需要了解 VitePress 提供了哪些插槽,请看 [布局插槽](https://vitepress.dev/zh/guide/extending-default-theme#layout-slots)。 Teek 并不是完全脱离 VitePress 的主题,而是基于 VitePress 的主题开发,所以 Teek 在入口组件里继承 VitePress 的 `Layout` 组件,并通过 VitePress 提供的插槽来实现功能。 Teek 的入口文件伴随着迭代,已经有很多内容产出,这里给出 Teek 早期的模板: ```vue ``` Teek 从 `theme` 中取出一个配置项 `teekTheme`,如果为 `true`,则使用 Teek 主题,否则使用 VitePress 的默认主题。 ::: tip `theme` 为项目里 `.vitepress/config.mts` 里的 `themeConfig` 内容。 ::: 如果您完全不需要基于 VitePress 的主题开发,则不需要使用 `DefaultTheme.Layout` 组件,直接在该组件写入自己的内容即可,这也意味着您只是基于 Vite 环境构建您的专属风格,您将自己实现首页、侧边栏、导航栏、CSS 样式等,只有 Markdown 解析的内容不需要自己实现,VitePress 已经提供了全局组件 `` 来渲染 Markdown 内容。 ::: tip 如果想完全脱离 VitePress 主题,在 `Layout` 函数处不要添加 `extends: DefaultTheme` ::: 在模板里可以看到这样两段代码: ```vue ``` * 第一段代码:Teek 不仅自己使用 VitePress 的插槽,同时也允许用户使用 VitePress 的插槽,所以 Teek 先维护了已使用的插槽列表,然后通过了 `v-for` 遍历所有 未使用 VitePress 的插槽,并使用 `#[name]="slotData"` 将插槽内容传递给 VitePress * 第二段代码:当不使用 Teek 主题时,则加载 VitePress 的默认主题,并使用 `v-for` 遍历所有插槽,将插槽内容传递给 VitePress。 如果不通过 `for` 循环,那么就需要这样写: ```vue ``` 可以看到 VitePress 提供的插槽非常多,这样写起来非常麻烦,因此建议使用 `for` 循环方式。 接下来就可以根据自己的需求来写组件,然后传入 VitePress 的插槽中,Teek 也是在模板里不断补充内容才达到现在的效果。 假设您已经自定义了首页和评论区组件,则需要传入 VitePress 的插槽中,内容如下: ```vue ``` 如果您不了解每个插槽分别作用于什么位置,可以在每个插槽里加一段文字如 `
${插槽名}
`,然后在页面查看输出的内容。 ## 引入主题 假设您已经开发好了一个主题,则需要在项目的 `.vitepress/theme/index.ts` 文件中引入,如果没有请按照该路径依次创建。 ```ts import Teek from "vitepress-theme-teek"; export default { extends: Teek, }; ``` 此时项目成功使用你的自定义主题。 --- --- url: /15.主题开发/70.开发技巧.md --- # 开发技巧 介绍 Teek 开发路程的一些技巧。 ## 规范 Teek 建议在进行项目开发时,一个文件的代码行数推荐 300 行以下,最好不超过 500 行,禁止超过 1000 行。 如果超过 300+ 行,应该考虑下是否可以拆分为多个文件,这是一个良好的 **结构化思维和分治思维**。 ::: tip Teek 建议您在开发前先思考有哪些模块,然后分别创建模块文件,而不是先在一个文件写完,再拆分。 ::: 举个例子: 代码合在一个文件: ```html

网站名称

``` 将代码进行模块化,根据功能/布局/逻辑等进行拆分: ```html
``` 假设您没有参与过该项目开发,现在由您来开始开发 `PostList` 模块的功能,我相信您更喜欢第二种,因为它已经明确的在向您挥手。 ## SSR 兼容 在 VitePress 主题开发时,请考虑 SSR 兼容性。否则在构建项目时,报错:`window/document is not defined`。 关于 SSR 兼容性,VitePress 官方提供了 [SSR 兼容性](https://vitepress.dev/zh/guide/ssr-compat) 的文档可以参考,文档里介绍了几个方式如何兼容 SSR。 但是 Teek 在这里提供一个 VitePress 官方没有 **直接** 说明的一种方式,这也是 Teek 兼容 SSR 的方式,即: **在任何访问浏览器或调用 DOM API 的代码前加上 SSR 环境校验**。 首先自定义一个 SSR 环境检验变量: ```ts const isClient = typeof window !== "undefined" && typeof document !== "undefined"; ``` 然后在使用 DOM API 之前加上这个校验,这样就防止构建时报错: ```vue {6} ``` 如果您的代码在 Vue 组件的 `beforeMount` 或 `mounted` 钩子中执行,则无需考虑 SSR,Vue 已经处理了。 ## 利用对象/数组减少 HTML 编写 ### 对象形式 **在 `template` 用 `if`、`if-else` 判断**。 ```vue ``` 可以将其转为对象: ```vue ``` 可以在组件 [Layout](https://github.com/Kele-Bingtang/vitepress-theme-teek/blob/master/packages/components/theme/Layout/index.vue) 的评论区相关代码或者 [HomeBanner](https://github.com/Kele-Bingtang/vitepress-theme-teek/blob/master/packages/components/theme/HomeBanner/src/index.vue) 查看具体使用。 ### 数组形式 **在 `template` 编写类似的重复 HTML**。 ```vue ``` 可以将其转为数组: ```vue ``` 仅限于重复度接近 90% 以上或者简单的 HTML,否则不建议使用数组 + `for` 循环,可读性会变差。 可以在组件 [ArticleInfo](https://github.com/Kele-Bingtang/vitepress-theme-teek/blob/master/packages/components/theme/ArticleInfo/src/index.vue) 查看具体使用。 ## 配置项支持方式 ### config 配置 如果配置项仅支持在 `.vitepress/config.mts` 配置: 在组件里这样使用: ```vue {6-9} ``` 这样避免了获取 `theme.xxx` 里的属性时报 `undefined`(没配置 `xxx`),同时如果 `theme.xxx` 里的某些属性没有配置,则赋予默认值。 ### config 和 frontmatter 配置 配置项同时支持在 `.vitepress/config.mts` 和 Markdown 的 `frontmatter` 配置,当两种都配置,则以 `frontmatter` 为准。 在组件里这样使用: ```vue ``` `frontmatter.value.tk.xxx` 是在首页 `index.md` 配置 `frontmatter` 时,额外添加了 `tk`,这是为了避免与 VitePress 自带配置的命名冲突。 支持 `frontmatter` 配置时,一定要用 `computed` 监听 `frontmatter` 变化,因为不同 Markdown 的 `frontmatter` 有可能不一样,如果没有监听 `frontmatter` 变化,会导致切换 Markdown 文章后,新文章的配置不会重新生效。 如: ::: code-group ```ts [config] // .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 [index.md] --- tk: comment: provider: "giscus" options: repo: "your repo" repoId: "your repoId" category: "your category" categoryId: "your categoryId" --- ``` ```yaml [文章页.md] --- comment: provider: "giscus" options: repo: "your repo" repoId: "your repoId" category: "your category" categoryId: "your categoryId" --- ``` ::: --- --- url: /01.指南/40.开发/01.开发指南.md --- # 开发指南 ## 开发环境 | 类型 | 名称 | 版本 | | :------------ | :---------------- | :--------------- | | 操作系统 | Windows 11 专业版 | 26100.3476 | | 开发工具 | Microsoft VS Code | 1.96.2 | | 调试工具 | Microsoft Edge | 134.0.3124.85 | | 代码版本控制 | Git | 2.47.0.windows.2 | | 语言环境 | Node | 22.12.0 | | 包管理器 | npm | 10.9.0 | | 包管理器 | pnpm | 9.15.4 | | node 版本管理 | nvm | 1.1.12 | | npm 源管理 | nrm | 1.2.6 | ## 项目结构 请看 [目录结构](/develop/catalogue)。 ## 克隆仓库 ```sh git clone https://github.com/Kele-Bingtang/vitepress-theme-teek.git ``` 如果 GitHub 克隆速度较慢,你也可以直接克隆 Gitee 上的镜像仓库,同步可能会存在时差。 ```sh git clone https://gitee.com/kele-bingtang/vitepress-theme-teek.git ``` ## 依赖安装 只能用 pnpm 安装依赖。 ```sh pnpm install ``` ## Teek 本地包构建 ```bash pnpm to:theme stub ``` ## 文档网站预览 ```sh pnpm docs:dev ``` ## 代码提交 ```sh pnpm cz # 仅提交本地 pnpm czp # 提交远程 ``` ::: tip 如果需要分次提交,可以先执行 `git add ./x/x`,再执行 `pnpm run git-cz`,最后执行 `git push origin dev`(或者其他分支)。 ::: ## Teek 打包 先构建 build 本地包 ```bash pnpm to:build stub ``` 最后执行打包 ```sh pnpm build ``` --- --- url: /@pages/archivesPage.md --- --- --- url: /20.资源/10.功能拓展/10.归档页贡献图.md --- # 归档页贡献图 什么是归档页贡献图?您可以在导航栏 功能页 -> 归档页 点击查看。 ## 安装 Echarts 依赖 首先需要安装 Echarts 依赖,根据您项目的包管理器选择安装方式: ::: code-group ```sh [pnpm] pnpm add -D echarts ``` ```sh [yarn] yarn add -D echarts ``` ```sh [npm] npm add -D echarts ``` ::: ## 创建贡献图组件 在 `.vitepress/theme/components` 目录下创建 `ContributeChart.vue` 文件,并添加以下代码: ```vue ``` 组件默认时间是近一年,且颜色已在代码里体现,您可以自行修改为你喜欢的风格。 ## 使用贡献图组件 在 `.vitepress/theme/index.ts` 中通过 Teek 提供的归档页顶部插槽插入贡献图组件。 ```ts import Teek from "vitepress-theme-teek"; import ContributeChart from "./components/ContributeChart.vue"; import { h } from "vue"; export default { extends: Teek, Layout: () => h(Teek.Layout, null, { "teek-archives-top-before": () => h(ContributeChart), }), }; ``` --- --- url: /01.指南/01.简介/10.快速开始.md description: Teek 是一个基于 VitePress 构建的主题,本文专门介绍如何快速安装 Teek。 --- # 快速开始 推荐 ## 版本 [![Teek badge](https://img.shields.io/npm/v/vitepress-theme-teek.svg?style=flat-square)](https://www.npmjs.org/package/vitepress-theme-teek) 建议使用如下包管理器安装 `vitepress-theme-teek`: * [pnpm](https://pnpm.io/) * [yarn](https://classic.yarnpkg.com/lang/en/) * [npm](https://www.npmjs.com/) ## 前言 如果你想快速构建一个和 Teek 文档类似的项目,可以直接拉取现成的 [Teek 文档模板仓库](https://github.com/Kele-Bingtang/vitepress-theme-teek-docs-template)。 ```sh git clone https://github.com/Kele-Bingtang/vitepress-theme-teek-docs-template.git ``` 如果你更喜欢从零开始慢慢研究 Teek,则可以按照下面的在线安装步骤构建并逐步丰富您的项目。 ## VitePress 安装 有关 VitePress 的安装教程来源于 [VitePress 文档](https://vitepress.dev/zh/guide/getting-started)。如果安装失败,请阅读 VitePress 文档查看最新的安装教程。 ::: code-group ```sh [pnpm] pnpm add -D vitepress ``` ```sh [yarn] yarn add -D vitepress ``` ```sh [npm] npm add -D vitepress ``` ::: VitePress 附带一个命令行设置向导,可以帮助你构建一个基本项目。安装后,通过运行以下命令启动向导: ::: code-group ```sh [pnpm] pnpm vitepress init ``` ```sh [yarn] yarn vitepress init ``` ```sh [npm] npx vitepress init ``` ::: 将需要回答几个简单的问题: ```sh ┌ Welcome to VitePress! │ ◇ Where should VitePress initialize the config? │ ./docs │ ◇ Where should VitePress look for your markdown files? │ ./docs │ ◇ Site title: │ My Awesome Project │ ◇ Site description: │ A VitePress Site │ ◇ Theme: │ Default Theme │ ◇ Use TypeScript for config and theme files? │ Yes │ ◇ Add VitePress npm scripts to package.json? │ Yes │ ◇ Add a prefix for VitePress npm scripts? │ Yes │ ◇ Prefix for VitePress npm scripts: │ docs │ └ Done! Now run pnpm run docs:dev and start writing. ``` ## Teek 在线安装 安装完 VitePress 后,执行命令安装 Teek: ::: code-group ```sh [pnpm] pnpm install vitepress-theme-teek -D ``` ```sh [yarn] yarn add vitepress-theme-teek -D ``` ```sh [npm] npm install vitepress-theme-teek -D ``` ::: ## Teek 引入 根据 VitePress 的要求,需要在 `.vitepress/theme/index.ts` 文件中引入 Teek 主题。如果没有该路径,需要先创建它: ```ts // .vitepress/theme/index.ts import Teek from "vitepress-theme-teek"; import "vitepress-theme-teek/index.css"; export default { extends: Teek, }; ``` 然后在 `.vitepress/config.mts` 文件中引入 Teek 的配置加载器: ```ts // .vitepress/config.mts import { defineConfig } from "vitepress"; import { defineTeekConfig } from "vitepress-theme-teek/config"; // Teek 主题配置 const teekConfig = defineTeekConfig({}); // VitePress 配置 export default defineConfig({ extends: teekConfig, // ... }); ``` 有关 Teek 更多的配置信息,请从 [配置简介](/reference/config) 开始阅读。 或者您直接看 [配置模板](https://github.com/Kele-Bingtang/vitepress-theme-teek/blob/main/docs/.vitepress/teekConfig.template.ts),该文件内容涵盖 Teek 95% 的配置项介绍,您可以根据需要复制出来。 ## 启动运行 请查看你的 `package.json` 文件,确保存在下面 npm 脚本: ```json { "scripts": { "docs:dev": "vitepress dev docs", "docs:build": "vitepress build docs", "docs:preview": "vitepress preview docs" } } ``` `docs:dev` 脚本将启动具有即时热更新的本地开发服务器。使用以下命令运行它: ::: code-group ```sh [pnpm] pnpm run docs:dev ``` ```sh [yarn] yarn docs:dev ``` ```sh [npm] npm run docs:dev ``` ::: `vitepress dev docs` 的 `docs` 并不是固定写死的,有三种场景可以进行选择: * 如果 `.vitepress` 和 Markdown 文档在项目根目录下,则 `vitepress dev docs` 改为 `vitepress dev` * 如果 `.vitepress` 和 Markdown 文档在项目 `src` 目录下,则 `vitepress dev docs` 改为 `vitepress dev src` * 如果 `.vitepress` 在项目根目录下,Markdown 文档放在 `src` 目录下,则 `vitepress dev docs` 改为 `vitepress dev`,且需要在 `.vitepress/config.mts` 里配置 `srcDir: src`,`srcDir` 的作用请看 [VitePress - srcDir](https://vitepress.dev/zh/reference/site-config#srcdir) 总结:VitePress 以 `.vitepress` 所在的目录层级 + `srcDir` 为参照逐层对 Markdown 文档扫描解析。 ## 版本更新 Teek 不定期提供新特性或者修复 Bug,届时只需要更新版本号即可: ::: code-group ```sh [pnpm] pnpm add vitepress-theme-teek@latest -D ``` ```sh [yarn] yarn add vitepress-theme-teek@latest -D ``` ```sh [npm] npm add vitepress-theme-teek@latest -D ``` ::: --- --- url: /01.指南/目录.md --- --- --- url: /10.配置/01.主题配置/40.插件配置.md --- # 插件配置 ## vitePlugins 内置 Vite 插件配置。 Teek 内置的 Vite 插件详细介绍请看 [Vite 插件](/guide/plugins)。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { sidebar: true, // 是否启用 sidebar 插件 sidebarOption: {}, // sidebar 插件配置项 permalink: true, // 是否启用 permalink 插件 permalinkOption: {}, // permalinks 插件配置项 mdH1: true, // 是否启用 mdH1 插件 catalogueOption: {}, // catalogues 插件配置项 docAnalysis: true, // 是否启用 docAnalysis 插件 docAnalysisOption: {}, // docAnalysis 插件配置项 fileContentLoaderIgnore: [], // fileContentLoader 插件扫描 markdown 文档时,指定忽略路径,格式为 glob 表达式,如 **/test/** autoFrontmatter: true, // 是否启用 autoFrontmatter 插件 // autoFrontmatter 插件配置项 autoFrontmatterOption: { permalinkPrefix: "pages", // 自动生成 permalink 的固定前缀,如 pages、pages/demo,默认为 pages categories: true, // 是否自动生成 categories // ... }, }, }); ``` ```ts [更多配置项] import type { PermalinkOption } from "vitepress-plugin-permalink"; import type { SidebarOption } from "vitepress-plugin-sidebar-resolve"; import type { CatalogueOption } from "vitepress-plugin-catalogue"; import type { DocAnalysisOption } from "vitepress-plugin-doc-analysis"; import type { AutoFrontmatterOption } from "plugins/vitepress-plugin-auto-frontmatter"; interface Plugins { /** * 是否启用 sidebar 插件 * * @default true */ sidebar?: boolean; /** * sidebar 插件配置项 */ sidebarOption?: SidebarOption; /** * 是否启用 permalink 插件 * * @default true */ permalink?: boolean; /** * permalinks 插件配置项 */ permalinkOption?: PermalinkOption; /** * 是否启用 mdH1 插件 * * @default true */ mdH1?: boolean; /** * catalogues 插件配置项 */ catalogueOption?: CatalogueOption; /** * 是否启用 docAnalysis 插件 * * @default true */ docAnalysis?: boolean; /** * docAnalysis 插件配置项 */ docAnalysisOption?: DocAnalysisOption; /** * fileContentLoader 插件扫描 markdown 文档时,指定忽略路径,格式为 glob 表达式,如 test/** * * @default [] */ fileContentLoaderIgnore?: string[]; /** * 是否启用 autoFrontmatter 插件 * * @default false */ autoFrontmatter?: boolean; /** * autoFrontmatter 插件配置项,并拓展出其他配置项 * * permalinkPrefix 为自动生成 permalink 的固定前缀,如 pages、pages/demo,默认为 page。当禁用 permalink 插件后,不会自动生成 permalink * categories 为是否自动生成 categories * * @default '{ permalinkPrefix: "pages", categories: true }' */ autoFrontmatterOption?: AutoFrontmatterOption & { permalinkPrefix?: string; categories?: boolean }; } ``` ::: ## markdown 您可以对 Teek 内置的 Markdown 容器进行一些配置。 Teek 内置的 Markdown 插件详细介绍请看 [Markdown 拓展](/guide/markdown)。 ### config 通过该 `config` 函数来加载更多的 `Markdown-it` 插件。 ::: danger 请不要使用 VitePress 提供的 `markdown.config` 函数来加载 `Markdown-it` 插件,因为 VitePress 方式会覆盖主题内置的 `Markdown-it` 插件。 ::: ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; import myMdPlugin from "my-md-plugin"; const teekConfig = defineTeekConfig({ markdown: { config: md => { md.use(myMdPlugin); }, }, }); ``` ```ts [更多配置项] import type MarkdownIt from "markdown-it"; Markdown { /** * 注册更多 markdown 插件函数 */ config?: (md: MarkdownIt) => void; } ``` ::: ### container Teek 内置的 Markdown 容器配置,配置项如下: ```ts interface Markdown { /** * 内置 markdown 容器的 Label 配置 */ container?: { /** * 自定义容器标题 */ label?: { /** * note 容器的默认标题 * * @default 'NOTE' */ noteLabel?: string; }; /** * 自定义 markdown 容器配置 */ config?: () => { /** * 容器类型 */ type: string; /** * 是否使用标题 */ useTitle?: boolean; /** * 默认标题 */ defaultTitle?: string; /** * 容器类名 */ className?: string; }[]; }; } ``` #### 容器配置 Note 容器默认的标题是 `Note`,您可以通过修改其默认值,这在国际化环境下很有帮助: ```ts // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; import myMdPlugin from "my-md-plugin"; const teekConfig = defineTeekConfig({ markdown: { container: { label: { noteLabel: "笔记", }, }, }, }); ``` #### 自定义容器 Teek 支持自定义 `Markdown` 容器配置。 通过 `markdown.container.config` 函数可以快速创建出类似于 Teek 内置的 `center` 和 `right` 容器或 VitePress 的 `info`、`tip`、`warning`、`danger` 容器。 先看例子: ```ts // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ markdown: { container: { config: () => [ { type: "demo1", useTitle: true, defaultTitle: "demo1", className: "demo1-container" }, { type: "demo2", useTitle: false, className: "demo2-container" }, ], }, }, }); ``` 示例中,我们创建了两个容器,其中第一个容器 `demo1` 通过 `useTitle: true` 来支持输入标题,如果不输入标题,则使用默认标题 `demo1`。 容器使用如下: ```markdown ::: demo1 测试 demo1 容器 ::: ::: demo1 容器标题 测试 demo1 容器 ::: ::: demo2 测试 demo2 容器 ::: ``` 生成的 HTML 结构如下: ```html

demo1

测试 demo1 容器

容器标题

测试 demo1 容器

测试 demo2 容器

${defaultTitle || 传入标题}

${输入的内容}

${输入的内容}

h(MyButton), }); }, }; ``` --- --- url: /01.指南/20.相关/02.插槽布局.md --- # 插槽布局 ## 插槽 Teek 提供了很多的插槽,能够被用来在页面的特定位置注入内容,下面这个例子展示了将一个组件注入到首页右侧卡片栏底部: ```ts // .vitepress/theme/index.ts import Teek from "vitepress-theme-teek"; import MyLayout from "./MyLayout.vue"; import "vitepress-theme-teek/index.css"; export default { extends: Teek, // 使用注入插槽的包装组件覆盖 Layout Layout: MyLayout, }; ``` ```vue ``` 也可以使用 `h` 渲染函数。 ```ts // .vitepress/theme/index.ts import Teek from "vitepress-theme-teek"; import "vitepress-theme-teek/index.css"; import { h } from "vue"; import MyComponent from "./components/MyComponent.vue"; export default { extends: Teek, Layout() { return h(Teek.Layout, null, { "teek-home-info-after": () => h(MyComponent), }); }, }; ``` Teek 主题的全部插槽如下: ## 首页插槽 当 `layout: 'home'` 在 frontmatter 中被启用时: * `teek-home-before`:等于 VitePress 的 `home-hero-before` 插槽 * `teek-home-after` 当首页为文档风格时启用: * `teek-home-features-before` * `teek-home-features-after` :等于 VitePress 的 `home-features-after` 插槽 ## Banner 插槽 * `teek-home-banner-before` * `teek-home-banner-after` * `teek-home-banner-content-before` * `teek-home-banner-content-after` * `teek-home-banner-feature-before` * `teek-home-banner-feature-after` * `teek-home-banner-name` :覆盖 Banner 的文字,利用该插槽可以使用组件美化标题。可以接收 1 个参数,即配置项传过来的 `name` 如下是 Teek 当前实现的效果示例: ```vue ``` ## 文章列表插槽 * `teek-home-post-before` * `teek-home-post-after` * `teek-home-post-list` Teek 默认实现了列表风格和卡片风格的文章列表,如果您需要定制自己的文章列表风格,可以通过 `teek-home-post-list` 插槽来覆盖 Teek 自带的文章列表,该插槽返回了当前的文章列表数量 `currentPosts`。 ```vue ``` v-bind 返回的 `transitionName` 为 post 配置项的 `transitionName`,具体可以查看 Teek 的列表风格和卡片风格的代码实现。 ## 卡片栏插槽 * `teek-home-card-before` * `teek-home-card` * `teek-home-card-after` * `teek-home-card-my-before` * `teek-home-card-my` * `teek-home-card-my-after` * `teek-home-card-my-avatar-after` * `teek-home-card-my-avatar-after` * `teek-home-card-top-article-before` * `teek-home-card-top-article` * `teek-home-card-top-article-after` * `teek-home-card-category-before` * `teek-home-card-category` * `teek-home-card-category-after` * `teek-home-card-tag-before` * `teek-home-card-tag` * `teek-home-card-tag-after` * `teek-home-card-friend-link-before` * `teek-home-card-friend-link` * `teek-home-card-friend-link-after` * `teek-home-card-doc-analysis-before` * `teek-home-card-doc-analysis` * `teek-home-card-doc-analysis-after` 移动端插槽: * `teek-home-card-my-screen-before` * `teek-home-card-my-screen` * `teek-home-card-my-screen-after` 不带 `-before` 和 `-after` 的插槽是直接覆盖卡片本身。 ## 底部插槽 * `teek-footer-info-before` * `teek-footer-info-after`:等于 VitePress 的 `layout-bottom` 插槽 * `teek-footer-info` * `teek-footer-group-before` * `teek-footer-group-after` ## 文章页插槽 当 `layout: 'doc'` 在 frontmatter 中被启用时: * `teek-article-analyze-before`:等于 VitePress 的 `doc-before` 插槽 * `teek-article-analyze-after` * `teek-article-share-before` * `teek-article-share-after`:等于 VitePress 的 `aside-outline-before` 插槽 * `teek-doc-after-appreciation-before`:等于 VitePress 的 `doc-after` 插槽 * `teek-doc-after-appreciation-after`:等于 Teek 的 `teek-comment-before` 插槽 * `teek-comment-before` * `teek-comment-after` * `teek-aside-bottom-appreciation-before`:等于 VitePress 的 `aside-bottom` 插槽 * `teek-aside-bottom-appreciation-after` * `teek-doc-update-before` * `teek-doc-update-after` * `teek-article-bottom-tip-before` * `teek-article-bottom-tip-after` * `teek-article-banner-before` :等于 VitePress 的 `layout-top` 插槽 * `teek-article-banner-after` * `teek-article-banner-info-top` * `teek-article-banner-info-bottom` ## 功能页插槽 当 `layout: 'page'` 在 frontmatter 中被启用时: * `teek-page-top-before`:等于 VitePress 的 `page-top` 插槽 * `teek-page-top-after` ### 归档页插槽 * `teek-archives-top-before` * `teek-archives-top-after` ### 目录页插槽 * `teek-catalogue-top-before` * `teek-catalogue-top-after` ### 登录页插槽 * `teek-login-page` :覆盖 Teek 的登录页,适用于自己实现一个登录页 ### 风险链接提示页 * `teek-risk-link-page` :覆盖 Teek 的风险链接提示页,适用于自己实现一个风险链接提示页 ## 全局插槽 ### 右下角按钮组插槽 * `teek-right-bottom-before` * `teek-right-bottom-after` * `teek-back-top` :覆盖回到顶部组件,可以接收 4 个参数: 1. show:是否显示,当处于顶部时为 false,往下滚动后为 true,可用于控制组件的显示 2. progress:当前滚动条的进度 3. icon:内置的默认图标 4. scrollToTop:回到顶部方法 如: ```vue ``` * `teek-to-comment` :覆盖滚动到评论区组件,可以接收 3 个参数: 1. show:是否显示,当处于评论区域时为 false,离开评论区域为 true,可用于控制组件的显示 2. icon:内置的默认图标 3. scrollToComment:滚动到评论区方法 如下是 Teek 当前实现的效果示例: ```vue ``` ::: tip 只有当页面存在评论区时,该功能/插槽才会生效。 ::: ### 其他插槽 * `teek-sidebar-trigger` :覆盖侧边栏展开/折叠触发器组件,可以接收 2 个参数: 1. active:点击触发器后为 `true`,`300s` 后为 `false`,目的是可以添加一个 `class` 或 `style` 来实现部分功能(过渡动画等) 2. icon:icon:内置的默认图标 3. toggleSideBar:点击触发器事件 如下是 Teek 当前实现的效果示例: ```vue ``` * `teek-loading` :切换页面(路由)时加载 Loading 动画,切换结束关闭 Loading 动画插槽,可以接收 1 个参数: 1. loading:开始切换页面(路由)时为 true,切换结束为 false 如下是 Teek 当前实现的效果示例: ```vue ``` ## 主题增强插槽 * `teek-theme-enhance-top` * `teek-theme-enhance-bottom` ## VitePress 插槽 其实官方也提供了不少 [插槽](https://vitepress.dev/zh/guide/extending-default-theme#layout-slots),可以按需使用。 例如 `not-found` 插槽可以帮我们自定义 404 页面。 配置过程: ### 新建 404.vue 新建 `docs\.vitepress\theme\components\404.vue` 文件,代码如下: ```vue ``` ### 新建 TeekLayoutProvider.vue 新建 `docs\.vitepress\theme\components\TeekLayoutProvider.vue`,在里面引用 `404.vue` 代码如下: ```vue ``` ### 引用 TeekLayoutProvider 在 `docs\.vitepress\theme\index.ts` 引用 `TeekLayoutProvider.vue`: ```ts import TeekLayoutProvider from "./components/TeekLayoutProvider.vue"; export default { extends: Teek, Layout: TeekLayoutProvider, }; ``` 说明: 1. `404.vue` 文件可以按需修改,网上有很多的模板参考(例如 [404s](https://www.404s.design/),[63 HTML 404 Templates](https://freefrontend.com/html-404-templates/)) 2. `TeekLayoutProvider.vue` 文件的作用是统一定义插槽。假如定义了很多页面,可以在这里统一引入 3. 然后在 `index.ts` 引入 `TeekLayoutProvider.vue` 文件即可 --- --- url: /01.指南/10.使用/10.摘要与封面.md --- # 摘要与封面 首页的文章列表中,可以显示文章摘要和封面图。 ## 文章摘要 文章摘要的设置有三种方式: * 使用 `frontmatter.description` 属性 * 使用 `` 注释 * 使用 `post.showCapture` 属性 如果三种方式都设置,只有一种生效,优先级为:使用 `frontmatter.description` 属性 > 使用 `` 注释 > 使用 `post.showCapture` 属性 ### frontmatter.description 属性 在文章页的 `frontmatter` 使用 `description` 来当作文章摘要。 ```yaml {5} --- title: Description 示例 date: 2024-10-27 23:14:44 permalink: /description/demo description: Teek 译为科技者、探索者,是一个神秘而富有诗意的探索者形象,同时有自然、坚韧、品质感的意象,以及一个连接自然与未来的中性符号,中文为天客。 --- ``` `description` 支持 HTML 文本,你可以添加一些 CSS 样式 ```yaml {5} --- title: Description 示例 date: 2024-10-27 23:14:44 permalink: /description/demo description: 'Teek 译为 科技者、探索者,是一个神秘而富有诗意的探索者形象,同时有自然、坚韧、品质感的意象,以及一个连接自然与未来的中性符号,中文为 天客。' --- ``` ::: warning HTML 文本必须使用引号包起来,否则报错。 ::: ### `` 注释 可以在首页的文章列表中,显示文章摘要。 在 Markdown 文档的某个位置添加 `` 注释,Teek 会自动将 `` 前的文本作为摘要,并且隐藏 `h1 ~ h3` 标题。 ```markdown ## 摘要示例 这是一段文章摘要,将会显示在首页的文章礼包,默认隐藏 `h1 ~ h3` 标题(摘要示例会被隐藏)。 ## 其他内容 这是一段其他内容。 ``` ::: tip 文章摘要会按照文章页的样式渲染,所以可以使用容器、链接、图片等功能。 摘要的内容也是文章内容的一部分,会显示在文章页中。 ::: ### post.showCapture 属性 Teek 支持截取 Markdown 文档里的文本作为文章摘要显示在文章列表上,默认截取前 300 个文本,但是实际显示的文本会根据文章列表的空间限制而改变。 在 Teek 的主题配置中,将 `post.showCapture` 设为 `true` 来启用该功能: ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ post: { showCapture: true, }, }); ``` ::: tip `post.showCapture` 开启后,文章列表的所有文章都会显示摘要内容。 ::: ### 文章摘要位置 Teek 支持通过 `post.excerptPosition` 设为 `top` 或 `bottom` 来改变文章摘要的位置。 文章摘要位置默认在文章列表的基本信息下面(`bottom`),可以将 `post.excerptPosition` 设为 `top` 来将文章摘要放在基本信息上面: ```ts {4-6} import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ post: { excerptPosition: "top", }, }); ``` ## 文章封面图 Teek 支持在文章列表中显示封面图,需要在 `frontmatter` 中添加 `coverImg` 字段,值为图片链接。 ```yaml {5} --- title: Description 示例 date: 2024-10-27 23:14:44 permalink: /description/demo coverImg: 图片地址 --- ``` ### 封面图模式 封面图支持 `small` 和 `full` 两个模式: * `small` 模式下,封面图会显示在文章列表的右边 * `full` 模式下,封面图会变大,尽量铺满整个空间(图片尺寸要足够),且奇数的文章列表封面图会显示在右边,偶数的文章列表封面图显示在左边。 封面图模式默认为 `full`,如果使用 `small` 模式,需要在 Teek 的主题配置中将 `post.coverImgMode` 设为 `small`: ```ts {4-6} import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ post: { coverImgMode: "small", }, }); ``` --- --- url: /personal.md --- # 支持这个项目 如果您正在使用这个项目并感觉这个项目给你带来帮助,或者是想支持我继续开发,您可以通过如下任意方式支持我: * Star 并分享 [VitePress Theme Teek](https://github.com/Kele-Bingtang/vitepress-theme-teek) 🚀 * 通过以下二维码进行赞助,打赏作者一杯茶 🍵 谢谢!❤️ | 微信赞赏 | 微信 | 支付宝 | | :--------------------------------------------------------------------------: | :--------------------------------------------------------------: | :----------------------------------------------------------: | | | | | 您的赞助将帮助 Teek: * 维护项目的基础设施 * 投入更多时间进行开发 * 提供更好的技术支持 * 开发更多实用功能 ## 致谢 ❤️ 感谢支持这个项目的朋友,您的每一份帮助都让这个项目变得更好! ❤️ 感谢为这个项目贡献代码的朋友 → [Contributors](https://github.com/Kele-Bingtang/vitepress-theme-teek/graphs/contributors) ## 赞助者名单 感谢以下赞助者对项目的支持。 Teek 会定期对赞助者名单更新,如果您已赞助但没有在名单中显示,请通过 Issue 或微信联系 Teek。(赞助金额至少达到 `¥9.9`) 赞助时可以备注如下内容: * 展示昵称,如果不指定昵称则取赞助的支付宝名/微信名 * 个人或公司网址,网址需为安全合法链接,否则不会添加或者下架网址;网址需要提供名称和链接,名单将会显示网址名称,点击网址名称跳转网址链接 * 不添加到赞助者名单 * 金额打码,比如 `50+`,`5*` | 赞助者 | 金额¥ | 日期 | 网址 | | ------------ | ------ | ---------- | ----------------------------------------------- | | 上官羽 | 59 | 2025-11-11 | [w3c](https://w3c.cool/) | | 。。。。。 | 10 | 2025-10-27 | | | One | 20 | 2025-09-10 | [One 博客](https://onedayxyy.cn) | | hubbub | 10 | 2025-09-03 | | | champ | 50 | 2025-08-31 | [公众号文章下载神器](https://docs.mptext.top/) | | 一云风一 | 50 | 2025-08-07 | | | Alowree | 100 | 2025-08-07 | [Alowree](https://marapython.com) | | 二丫讲梵 | 20 | 2025-08-07 | [二丫讲梵博客](https://eryajf.net) | | 时光 | 10 | 2025-08-07 | [时光](https://notes.ksah.cn) | | 马九溪 | 66 | 2026-04-03 | | | 天坠 | 66 | 2026-04-12 | [天坠](https://172.tianzhuicn.cn) | | ALiaoHaolong | 20 | 2026-05-18 | [ALiaoHaolong](https://aliaohaolong.github.io/) | --- --- url: /10.配置/01.主题配置/15.文章列表配置.md --- # 文章列表配置 ## post 文章列表配置。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ post: { postStyle: "list", // 文章列表风格 excerptPosition: "top", // 文章摘要位置 showMore: true, // 是否显示更多按钮 moreLabel: "阅读全文 >", // 更多按钮文字 emptyLabel: "暂无文章", // 文章列表为空时的标签 coverImgMode: "full", // 文章封面图模式 showCapture: false, // 是否在摘要位置显示文章部分文字,当为 true 且不使用 frontmatter.describe 和 时,会自动截取前 300 个字符作为摘要 splitSeparator: false, // 文章信息(作者、创建时间、分类、标签等信息)是否添加 | 分隔符 transition: true, // 是否开启过渡动画 transitionName: "tk-slide-fade", // 自定义过渡动画名称 listStyleTitleTagPosition: "right", // 列表模式下的标题标签位置(postStyle 为 list) cardStyleTitleTagPosition: "left", // 卡片模式下的标题标签位置(postStyle 为 card) defaultCoverImg: [], // 默认封面图地址,如果不设置封面图则使用默认封面图地址 }, }); ``` ```yaml [index.md] --- tk: post: postStyle: list excerptPosition: top showMore: true moreLabel: "阅读全文 >" coverImgMode: full emptyLabel: 暂无文章 showCapture: false splitSeparator: false transition: true transitionName: tk-slide-fade listStyleTitleTagPosition: right cardStyleTitleTagPosition: left --- ``` ```ts [更多配置项] import type { TitleTagProps } from "vitepress-theme-teek"; interface Post { /** * 文章模板风格,list 为列表风格,card 为卡片风格 * * @since v1.1.5 * @default list */ postStyle?: "list" | "card"; /** * 文章摘要位置 * * @default bottom */ excerptPosition?: "top" | "bottom"; /** * 是否显示更多按钮 * * @default true */ showMore?: boolean; /** * 更多按钮文字 * * @default '阅读全文 >' */ moreLabel?: string; /** * 文章列表为空时的标签 * * @default '暂无文章' */ emptyLabel?: string; /** * 文章封面图模式 * * @default 'small' */ coverImgMode?: "small" | "full"; /** * 是否在摘要位置显示文章部分文字,当为 true 且不使用 frontmatter.describe 和 `` 时,会自动截取前 300 个字符作为摘要 * * @default false */ showCapture?: boolean; /** * 文章信息(作者、创建时间、分类、标签等信息)是否添加 | 分隔符 * * @default false */ splitSeparator?: boolean; /** * 是否开启过渡动画 * * @default true */ transition?: boolean; /** * 自定义过渡动画名称 * * @default 'tk-slide-fade' */ transitionName?: string; /** * 列表模式下的标题标签位置(postStyle 为 list) * * @since v1.1.5 * @default 'right' */ listStyleTitleTagPosition?: TitleTagProps["position"]; /** * 卡片模式下的标题标签位置(postStyle 为 list) * * @since v1.1.5 * @default 'left' */ cardStyleTitleTagPosition?: TitleTagProps["position"]; /** * 默认封面图地址,如果不设置封面图则使用默认封面图地址 * * @since v1.2.1 * @default [] */ defaultCoverImg?: string[]; } ``` ::: 您可以通过 `postStyle` 配置项来设置文章列表的风格: * 当 `postStyle` 为 `list` 时,文章列表为列表风格 * 当 `postStyle` 为 `card` 时,文章列表为卡片风格,且 `excerptPosition`、`showMore`、`moreLabel`、`coverImgMode` 配置项失效 ## page 首页 Post 文章列表的分页配置,完全是 [ElPagination](https://element-plus.org/zh-CN/component/pagination.html#api) 的 props。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ page: { disabled: false, // 是否禁用 pageSize: 20, // 每页显示条目数 pagerCount: 7, // 设置最大页码按钮数。 页码按钮的数量,当总页数超过该值时会折叠 layout: "prev, pager, next, jumper, ->, total", // 组件布局,子组件名用逗号分隔 size: "default", // 分页大小 background: false, // 是否为分页按钮添加背景色 hideOnSinglePage: false, // 只有一页时是否隐藏 // ... }, }); ``` ```yaml [index.md] --- tk: page: disabled: false pageSize: 20 pagerCount: 7 layout: "prev, pager, next, jumper, ->, total" size: default background: false hideOnSinglePage: false --- ``` ```ts [更多配置项] import type { IconProps } from "vitepress-theme-teek"; interface TeekConfig { /** * 首页 Post 文章列表的分页配置 */ page?: { /** * 是否禁用 * * @default false */ disabled?: boolean; /** * 总条目数 */ total?: number; /** * 每页显示条目数 */ pageSize?: number; /** * 总页数,与 total 二选一 */ pageCount?: number; /** * 设置最大页码按钮数。 页码按钮的数量,当总页数超过该值时会折叠 * * @default 7 */ pagerCount?: number; /** * 组件布局,子组件名用逗号分隔 * * @default 'prev, pager, next, jumper, ->, total' */ layout?: string; /** * 替代图标显示的上一页文字 */ prevText?: string; /** * 上一页的图标, 比 prev-text 优先级更高 */ prevIcon?: IconProps["icon"]; /** * 替代图标显示的下一页文字 */ nextText?: string; /** * 下一页的图标, 比 next-text 优先级更高 */ nextIcon?: IconProps["icon"]; /** * 分页大小 * * @default 'default' */ size?: Size; /** * 是否为分页按钮添加背景色 * * @default false */ background?: boolean; /** * 只有一页时是否隐藏 * * @default false */ hideOnSinglePage?: boolean; }; } ``` ::: --- --- url: /@pages/articleOverviewPage.md --- --- --- url: /10.配置/01.主题配置/30.文章配置.md --- # 文章配置 ## articleBanner 文章页顶部 Banner,仅在没有侧边栏的文章页生效,如果您还不了解什么是 `ArticleBanner` ,请查看 [ArticleBanner](/demo/articleBanner1) 示例。 文章页 Banner 的背景色支持封面图和背景色 2 个类型: 1. 封面图:读取 `frontmatter.coverImg` 的属性,如果获取不到,则使用配置文件的 `articleBanner.defaultCoverImg`,如果依然获取不到,则走背景色逻辑 2. 背景色:读取 `frontmatter.coverBgColor` 的属性,如果获取不到,则使用配置文件的 `articleBanner.defaultCoverBgColor`,如果依然获取不到,则使用主题色作为默认的背景色 为了防止封面图过于亮导致文字无法看见,Teek 会使用背景色来降低封面图的亮色,因此 **最合理的使用是同时配置封面图和背景色,且背景色的值应该和封面图颜色一致**。 ::: tip Teek 提供的封面图样式会将封面图稍微放大,然后添加模糊效果,这样也许不满足你的需求,你可以自行修改样式。 ::: ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ articleBanner: { enabled: true, // 是否启用单文章页 Banner showCategory: true, // 是否展示分类 showTag: true, // 是否展示标签 defaultCoverImg: "", // 默认封面图 defaultCoverBgColor: "", // 默认封面背景色,优先级低于 defaultCoverImg }, }); ``` ```yaml [文章页 xxx.md] --- articleBanner: enabled: true showCategory: true showTag: true coverImg: "" coverBgColor: "" --- ``` ```ts [更多配置项] interface ArticleBanner { /** * 是否启用单文章页 Banner * * @default false */ enabled?: boolean; /** * 是否展示分类 * * @default true */ showCategory?: boolean; /** * 是否展示标签 * * @default true */ showTag?: boolean; /** * 默认封面图 */ defaultCoverImg?: string; /** * 默认封面背景色,优先级低于 defaultCoverImg */ defaultCoverBgColor?: string; } ``` ::: 如果您想修改 `ArticleBanner` 的面包屑配置,如隐藏面包屑,请往下参阅 [breadcrumb](#breadcrumb) 的配置。 如果您想隐藏 `ArticleBanner` 的作者、日期、字数、阅读时长等信息,请往下参阅 [articleAnalyze](#articleAnalyze) 的配置。 ::: tip 使用了 `ArticleBanner`,则 `articleAnalyze` 的 `showCategory` 和 `showTag` 配置将无效。如果想隐藏分类和标签,直接通过 `articleBanner.showCategory` 和 `articleBanner.showTag` 配置。 ::: ## articleAnalyze 文章信息分析配置,分别作用在首页和文章页。 ::: tip 如果在 `config.mts` 中配置,则首页和文章页都生效。 文章页的图片点击可以预览,但是当图片元素的 class 里存在 `no-preview`,则不会触发预览,这对于兼容 Teek 的图片相关插件有所帮助。 ::: ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ articleAnalyze: { showIcon: true, // 作者、日期、分类、标签、字数、阅读时长、浏览量等文章信息的图标是否显示 dateFormat: "yyyy-MM-dd hh:mm:ss", // 文章日期格式,首页和文章页解析日期时使用 dateUTC: true, // 是否使用 UTC 时间 showInfo: true, // 是否展示作者、日期、分类、标签、字数、阅读时长、浏览量等文章信息,分别作用于首页和文章页 showAuthor: true, // 是否展示作者 showCreateDate: true, // 是否展示创建日期 showUpdateDate: false, // 是否展示更新日期,仅在文章页显示 showCategory: false, // 是否展示分类 showTag: false, // 是否展示标签 }, }); ``` ```yaml [首页 index.md] --- tk: articleAnalyze: showIcon: true dateFormat: yyyy-MM-dd hh:mm:ss dateUTC: true showInfo: true showAuthor: true showCreateDate: true showUpdateDate: false showCategory: false showTag: false --- ``` ```yaml [文章页 xxx.md] --- articleAnalyze: showIcon: true dateFormat: yyyy-MM-dd hh:mm:ss dateUTC: true showInfo: true showAuthor: true showCreateDate: true showUpdateDate: false showCategory: false showTag: false --- ``` ```ts [更多配置项] interface Article { /** * 作者、日期、分类、标签、字数、阅读时长、浏览量等文章信息的图标是否显示 * * @default true */ showIcon?: boolean; /** * 文章日期格式,首页和文章页解析日期时使用 * * @default 'yyyy-MM-dd' */ dateFormat?: "yyyy-MM-dd" | "yyyy-MM-dd hh:mm:ss" | ((date: string) => string); /** * 是否使用 UTC 时间 * * @default true */ dateUTC?: boolean; /** * 是否展示作者、日期、分类、标签、字数、阅读时长、浏览量等文章信息,分别作用于首页和文章页 * 如果 showInfo 为数组,则控制在哪里显示,如 ["post"] 只在首页的 Post 列表显示基本信息;如果为 boolean 值,则控制基本信息是否展示,如 false 则在首页和文章页都不显示基本信息 * * @default true */ showInfo?: boolean | ArticleInfoPosition[]; /** * 是否展示作者 * * @default true */ showAuthor?: boolean | ArticleInfoPosition[]; /** * 是否展示创建日期 * * @default true */ showCreateDate?: boolean | ArticleInfoPosition[]; /** * 是否展示更新日期,仅在文章页显示 * * @default false */ showUpdateDate?: boolean; /** * 是否展示分类 * * @default false */ showCategory?: boolean | ArticleInfoPosition[]; /** * 是否展示标签 * * @default false */ showTag?: boolean | ArticleInfoPosition[]; /** * 指定文章信息的传送位置,仅限在文章页生效,默认在文章页顶部 */ teleport?: { /** * 指定需要传送的元素选择器 */ selector?: string; /** * 指定传送到元素的位置,before 在元素前,after 在元素后 * * @default 'after' */ position?: "before" | "after"; /** * 指定一个 class 名,如果传送的位置和其他元素太接近,可以利用 class 来修改 margin * * @default teleport */ className?: string; }; /** * 文章页图片查看器配置 */ imageViewer?: Partial; } ``` ::: 配置项中,`teleport` 可以将文章信息传送到指定位置,仅限在文章页生效,默认在文章页顶部。 如将文章信息传到一级标题下面: ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ articleAnalyze: { teleport: { selector: "h1", position: "after", className: "h1-bottom-info", }, }, }); ``` ```yaml [文章页 xxx.md] --- tk: articleAnalyze: teleport: selector: h1 position: after className: h1-bottom-info --- ``` ::: 配置项中,`imageViewer` 是文章页图片查看器的配置,如果您想禁用图片预览功能 ,则进行如下配置: ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ articleAnalyze: { imageViewer: { enabled: false, // 禁用图片查看器 }, }, }); ``` ```yaml [文章页 xxx.md] --- tk: articleAnalyze: imageViewer: enabled: false --- ``` ```ts [更多配置项] interface ImageViewerProps { /** * 是否启用图片查看器 * * @default true * @since v1.5.7 */ enabled?: boolean; /** * 预览时遮罩层的 z-index */ zIndex?: number; /** * 是否可以通过点击遮罩层关闭预览 * * @default false */ hideOnClickModal?: boolean; /** * image 自身是否插入至 body 元素上。 嵌套的父元素属性会发生修改时应该将此属性设置为 true * * @default false */ teleported?: boolean; /** * 是否可以通过按下 ESC 关闭 Image Viewer * * @default true */ closeOnPressEscape?: boolean; /** * 图像查看器缩放事件的缩放速率 * * @default 1.2 */ zoomRate?: number; /** * 图像查看器缩放事件的最小缩放比例 * * @default 0.2 */ minScale?: number; /** * 图像查看器缩放事件的最大缩放比例 * * @default 7 */ maxScale?: number; /** * 是否显示预览图片的进度条内容 * * @default false */ showProgress?: boolean; /** * 原生属性 crossorigin */ crossorigin?: "anonymous" | "use-credentials" | ""; } ``` ::: ## breadcrumb 面包屑配置。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ breadcrumb: { enabled: true, // 是否启用面包屑 showCurrentName: false, // 面包屑最后一列是否显示当前文章的文件名 separator: "/", // 面包屑分隔符 homeLabel: "首页", // 鼠标悬停首页图标的提示文案 }, }); ``` ```yaml [文章页 xxx.md] --- tk: breadcrumb: enabled: true showCurrentName: false separator: / homeLabel: 首页 --- ``` ```ts [更多配置项] interface Breadcrumb { /** * 是否启用面包屑 * * @default true */ enabled?: boolean; /** * 面包屑最后一列是否显示当前文章的文件名 * * @default false */ showCurrentName?: boolean; /** * 面包屑分隔符 * * @default '/' */ separator?: string; /** * 鼠标悬停首页图标的提示文案 * * @default '首页' */ homeLabel?: string; } ``` ::: ## pageStyle * 类型:`"default" | "card" | "segment" | "card-nav" | "segment-nav"` * 默认值:`default` 文章页的样式风格,`default` 为 VitePress 原生风格,`card` 为单卡片风格,`segment` 为片段卡片风格,`card-nav` 和 `segment-nav` 会额外修改导航栏样式。 ::: tip 在文章页的 `frontmatter` 配置 `pageStyle`,可以针对不同的文章页开启不同的样式风格。 ::: 如果使用了主题增强的布局尺寸切换,且布局尺寸不是 VitePress 默认尺寸,则该配置项失效 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ pageStyle: "segment-nav", }); ``` ```yaml [文章页 xx.md] --- pageStyle: segment-nav --- ``` ::: ## appreciation 赞赏功能配置。 赞赏功能提供 3 个位置选择: * `doc-after`:文章页底部,评论区上方 * `doc-after-popper`:文章页底部,评论区上方,以弹框形式出现 * `aside-bottom`:文章页大纲栏下方 每个位置分别有不同的配置项。 ::: code-group ```ts [文章页底部] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ appreciation: { position: "doc-after", // 赞赏位置 // 赞赏配置 options: { icon: "weChatPay", // 赞赏图标,内置 weChatPay 和 alipay expandTitle: "打赏支持", // 展开标题,支持 HTML collapseTitle: "下次一定", // 折叠标题,支持 HTML content: ``, // 赞赏内容,支持 HTML expand: false, // 是否默认展开,默认 false }, }, }); ``` ```ts [文章页底部 Popper] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ appreciation: { position: "doc-after-popper", // 赞赏位置 // 赞赏配置 options: { trigger: "click", // 触发方式 icon: "weChatPay", // 赞赏图标,内置 weChatPay 和 alipay title: "打赏支持", // 展开标题,支持 HTML content: ` `, // 赞赏内容,支持 HTML }, }, }); ``` ```ts [文章页大纲栏下方] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ appreciation: { position: "aside-bottom", // 赞赏位置 // 赞赏配置 options: { title: `欢迎打赏支持`, // 赞赏标题,支持 HTML content: ``, // 赞赏内容,支持 HTML }, }, }); ``` ```ts [更多配置项] import type { IconProps } from "vitepress-theme-teek"; type Appreciation = { /** * 赞赏位置 */ position?: T; /** * 赞赏配置 */ options?: AppreciationPosition[T]; }; type AppreciationPosition = { "": object; "aside-bottom": { /** * 赞赏标题,支持 HTML */ title?: string; /** * 赞赏内容,支持 HTML */ content?: string; }; "doc-after": { /** * 自定义按钮 HTML */ buttonHtml?: string; /** * 赞赏图标,内置 weChatPay 和 alipay */ icon?: IconProps["icon"] | "weChatPay" | "alipay"; /** * 展开标题,支持 HTML */ expandTitle?: string; /** * 折叠标题,支持 HTML */ collapseTitle?: string; /** * 赞赏内容,支持 HTML */ content?: string; /** * 是否默认展开 * * @default false */ expand?: boolean; }; "doc-after-popper": { /** * 触发方式 * * @default "click" */ trigger?: "click" | "hover"; /** * 自定义按钮 HTML */ buttonHtml?: string; /** * 赞赏图标,内置 weChatPay 和 alipay */ icon?: IconProps["icon"] | "weChatPay" | "alipay"; /** * 赞赏标题,支持 HTML */ title?: string; /** * 赞赏内容,支持 HTML */ content?: string; }; }; ``` ::: Teek 内置两个 icon: * `weChatPay`:微信支付图标 * `alipay`:支付宝图标 如果您需要自定义图标,则通过 `icon` 配置项传入。 赞赏功能同样支持在单个 Markdown 的 `frontmatter` 配置来覆盖全局配置。 ```yaml --- appreciation: position: doc-after options: icon: weChatPay expandTitle: 打赏支持 collapseTitle: 下次一定 content: "" expand: false --- ``` ## articleShare 文章分享配置。 本功能主要是在文章右侧的大纲栏添加一个按钮,点击后自动复制文章链接到剪贴板。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ articleShare: { enabled: true, // 是否开启文章链接分享功能 text: "分享此页面", // 分享按钮文本 copiedText: "链接已复制", // 复制成功文本 query: false, // 是否包含查询参数 hash: false, // 是否包含哈希值 }, }); ``` ```yaml [文章页 xx.md] --- articleShare: enabled: true text: 分享此页面 copiedText: 链接已复制 query: false hash: false --- ``` ```ts [更多配置项] import type { IconProps } from "vitepress-theme-teek"; interface ArticleShare { /** * 是否开启文章链接分享功能 * * @default false */ enabled?: boolean; /** * 分析按钮图标 */ icon?: IconProps["icon"]; /** * 分享按钮文本 * * @default '分享此页面' */ text?: string; /** * 复制成功图标 */ copiedIcon?: IconProps["icon"]; /** * 复制成功文本 * * @default '链接已复制' */ copiedText?: string; /** * 是否包含查询参数 * * @default false */ query?: boolean; /** * 是否包含哈希值 * * @default false */ hash?: boolean; } ``` ::: ## articleTopTip 在每个文章页顶部显示 VitePress 容器添加提示,使用场景如超过半年的文章自动提示文章内容可能已过时。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ articleTopTip: (frontmatter, localeIndex, page) => { const tip: Record = { type: "warning", text: "文章发布较早,内容可能过时,阅读注意甄别。", }; // 大于半年,添加提示 const longTime = 6 * 30 * 24 * 60 * 60 * 1000; if (frontmatter.date && Date.now() - new Date(frontmatter.date).getTime() > longTime) return tip; }, }); ``` ```ts [类型] import type { PageData } from "vitepress"; import type { VpContainerProps } from "@teek/components/common/VpContainer/src/vpContainer"; interface TeekConfig { /** * 文章页顶部使用 VitePress 容器添加提示 * * @param frontmatter 文档 frontmatter * @param localeIndex 当前国际化语言 * @param page 文章信息,即 useData().page 的信息 */ articleTopTip?: ( frontmatter: PageData["frontmatter"], localeIndex: string, page: PageData ) => VpContainerProps | undefined; } ``` ::: 如果全局开启了该功能,但希望在某个文章页隐藏该功能,有两种方式实现: * `frontmatter.articleTopTip` 设置为 `false` * 在 `config.ts` 中配置 `articleTopTip` 时,第一个参数为 `frontmatter`,因此可以在函数自定义判断,如 `if(frontmatter.topTip === false) return`,那么就可以在 Markdown 的 `frontmatter.topTip` 设置为 `false` ## articleBottomTip 在每个文章页顶部显示 VitePress 容器添加提示,使用场景如添加文章版权声明。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ articleBottomTip: frontmatter => { if (typeof window === "undefined") return; const hash = false; const query = false; const { origin, pathname, search } = window.location; const url = `${origin}${frontmatter.permalink ?? pathname}${query ? search : ""}${hash ? location.hash : ""}`; const author = "Teek"; return { type: "tip", // title: "声明", // 可选 text: `

作者:${author}

链接:${decodeURIComponent(url)}

版权:此文章版权归 ${author} 所有,如有转载,请注明出处!

`, }; }, }); ``` ```ts [类型] import type { PageData } from "vitepress"; import type { VpContainerProps } from "@teek/components/common/VpContainer/src/vpContainer"; interface TeekConfig { /** * 文章页底部使用 VitePress 容器添加提示 * * @param frontmatter 文档 frontmatter * @param localeIndex 当前国际化语言 * @param page 文章信息,即 useData().page 的信息 */ articleBottomTip?: ( frontmatter: PageData["frontmatter"], localeIndex: string, page: PageData ) => VpContainerProps | undefined; } ``` ::: 如果全局开启了该功能,但希望在某个文章页隐藏该功能,有两种方式实现: * `frontmatter.articleBottomTip` 设置为 `false` * 在 `config.ts` 中配置 `articleBottomTip` 时,第一个参数为 `frontmatter`,因此可以在函数自定义判断,如 `if(frontmatter.bottomTip === false) return`,那么就可以在 Markdown 的 `frontmatter.bottomTip` 设置为 `false` ## articleUpdate 文章页底部的最近更新栏配置。 ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ articleUpdate: { enabled: true, // 是否启用文章最近更新栏 limit: 3, // 文章最近更新栏显示数量 }, }); ``` ```yaml [文章页1 xx.md] --- articleShare: false # 禁用文章分享栏 --- ``` ```yaml [文章页2 xx.md] --- articleShare: enabled: true limit: 3 --- ``` ```ts [更多配置项] interface ArticleUpdate { /** * 是否启用文章最近更新栏 * * @since v1.2.1 * @default true */ enabled?: boolean; /** * 文章最近更新栏显示数量 * * @since v1.2.1 * @default 3 */ limit?: number; } ``` ::: --- --- url: /20.资源/10.功能拓展/15.日历卡片.md --- # 日历卡片 什么是日历卡片?您可以在博客风格首页的卡片栏看到效果。 ## 创建日历卡片组件 在 `.vitepress/theme/components` 目录下创建 `CalendarCard.vue` 文件,并添加以下代码: ```vue ``` ## 使用日历卡片组件 在 `.vitepress/theme/index.ts` 中通过 Teek 提供的卡片栏插槽插入日历卡片组件。 ```ts import Teek from "vitepress-theme-teek"; import CalendarCard from "./components/CalendarCard.vue"; import { h } from "vue"; export default { extends: Teek, Layout: () => h(Teek.Layout, null, { "teek-home-card-my-after": () => h(CalendarCard), }), }; ``` --- --- url: /@pages/tagsPage.md --- --- --- url: /01.指南/10.使用/20.样式增强.md --- # 样式增强 Teek 提供了一些样式文件来增强 VitePress 和 Teek 的样式。 比如现在看到的一级标题渐变色,如果只是单纯安装 Teek 是不会有这个效果,需要引入 Teek 内置的样式增强文件来实现: ```ts // .vitepress/theme/index.ts import "vitepress-theme-teek/theme-chalk/tk-doc-h1-gradient.css"; ``` > VitePress * 首页图片背景添加彩色渐变动画 * 文章一级标题添加渐变色 * 侧边栏标题组字号加粗 * VitePress 内容容器样式增强 * 导航栏样式增强 * 侧边栏样式增强 * ... > Teek * 首页 Banner 描述添加渐变效果 * 首页 Banner 壁纸添加缩放动画 * 首页卡片悬停效果增强 这些样式增强文件并不会默认开启,而是需要您自行引入来开启。 ## VitePress 样式增强 在 [vp-plus](https://github.com/Kele-Bingtang/vitepress-theme-teek/tree/main/packages/theme-chalk/src/vp-plus) 目录下查看所有的样式样式增强文件内容。 SCSS 文件如下(可能不全): ```sh vp-plus. ├─ aside.scss # 右侧目录栏文字悬停和激活样式 ├─ blockquote.scss # > 引用块样式 ├─ brand-color-animation.scss # 主题色定时切换 ├─ code-block-mobile.scss # 代码块移动端样式 ├─ container-bg.scss # 容器背景样式更改,内置 container-var ├─ container-flow.scss # container-fluid + container-icon 组合 ├─ container-fluid.scss # 容器流体样式 ├─ container-icon.scss # 容器 ICON 样式 ├─ container-left.scss # 容器左侧框样式 ├─ container-var.scss # 容器 css var 变量 ├─ container.scss # container-bg + container-icon + container-var 组合 ├─ doc-fade-in.scss # 文章页淡入效果 ├─ doc-h1-gradient.scss # 文章一级标题渐变色 ├─ index-rainbow.scss # 首页图片彩虹动画 ├─ mark.scss # 文章内容标记样式(mark 标签) ├─ nav-blur.scss # 导航栏毛玻璃样式 ├─ nav-search-button.scss # 导航栏搜索按钮样式 ├─ nav-switch-button.scss # 导航栏深色、浅色模式切换按钮样式 ├─ nav-translation.scss # 导航栏国际化下拉样式 ├─ nav.scss # nav-search-button + nav-switch-button + nav-translation 组合 ├─ scrollbar.scss # 滚动条样式 ├─ sidebar.scss # 侧边栏样式 ├─ table.scss # 表格样式调整,去掉单元格之间的线条 ``` 在 `.vitepress/theme/index.ts` 按需引入(css 文件需要以 `tk-` 开头): ```ts // .vitepress/theme/index.ts import "vitepress-theme-teek/theme-chalk/tk-code-block-mobile.css"; import "vitepress-theme-teek/theme-chalk/tk-sidebar.css"; import "vitepress-theme-teek/theme-chalk/tk-aside.css"; import "vitepress-theme-teek/theme-chalk/tk-nav.css"; import "vitepress-theme-teek/theme-chalk/tk-doc-h1-gradient.css"; import "vitepress-theme-teek/theme-chalk/tk-doc-fade-in.css"; // ... ``` 如果您的项目有 `scss` 依赖,可以直接引入 `scss` 样式文件: ```ts // .vitepress/theme/index.ts import "vitepress-theme-teek/vp-plus/code-block-mobile.scss"; import "vitepress-theme-teek/vp-plus/sidebar.scss"; import "vitepress-theme-teek/vp-plus/aside.scss"; import "vitepress-theme-teek/vp-plus/nav.scss"; import "vitepress-theme-teek/vp-plus/doc-h1-gradient.scss"; import "vitepress-theme-teek/vp-plus/doc-doc-fade-in.scss"; // ... ``` ## Teek 样式增强 在 [tk-plus](https://github.com/Kele-Bingtang/vitepress-theme-teek/tree/main/packages/theme-chalk/src/tk-plus) 目录下查看所有的样式样式增强文件内容。 样式文件如下(可能不全): ```sh tk-plus. ├─ banner-desc-gradient.scss # 首页 Banner 描述添加渐变效果 ├─ banner-full-img-scale.scss # 首页 Banner 壁纸添加缩放动画 ├─ fade-up-animation.scss # 首次进入页面添加渐显动画 ├─ home-card-hover.scss # 首页卡片悬停效果 ``` 在 `.vitepress/theme/index.ts` 按需引入(css 文件需要以 `tk-` 开头): ```ts // .vitepress/theme/index.ts import "vitepress-theme-teek/theme-chalk/tk-banner-desc-gradient.css"; import "vitepress-theme-teek/theme-chalk/tk-banner-full-img-scale.css"; import "vitepress-theme-teek/theme-chalk/tk-fade-up-animation.css"; import "vitepress-theme-teek/theme-chalk/tk-home-card-hover.css"; // ... ``` 如果您的项目有 `scss` 依赖,可以直接引入 `scss` 样式文件: ```ts // .vitepress/theme/index.ts import "vitepress-theme-teek/tk-plus/banner-desc-gradient.scss"; import "vitepress-theme-teek/tk-plus/banner-full-img-scale.scss"; import "vitepress-theme-teek/tk-plus/fade-up-animation.scss"; import "vitepress-theme-teek/tk-plus/home-card-hover.scss"; // ... ``` ## 功能增强 ### 复制提示 Teek 提供 **复制提示** 功能,当复制文本时,会在顶部添加一些提示语,在 `.vitepress/theme/index.ts` 中引入并使用: ```ts // .vitepress/theme/index.ts import Teek, { useCopyBanner } from "vitepress-theme-teek"; import "vitepress-theme-teek/index.css"; export default { extends: Teek, Layout: TeekLayoutProvider, setup: () => { // 使用复制提示功能(默认配置) useCopyBanner(); /** * 配置方式,可自定义提示语 * * 1. 提示语。默认:复制成功,复制和转载请标注本文地址 * 2. 显示的持续时间(毫秒),默认 3000 */ // useCopyBanner("复制成功", 4000); }, }; ``` --- --- url: /15.主题开发/40.样式布局.md --- # 样式布局 ## 样式与组件分离 Teek 并没有和普通的 Vue 项目一样,使用如下模板进行编写组件: ```vue ``` 而是使用: ```vue ``` 那么组件样式去哪里了呢? Teek 专门创建 `theme-chalk/src/components` 目录用于存放组件样式,然后将所有的组件样式汇总到一个 `index.scss`(入口样式文件),最后在 `index.ts`(入口运行文件)分别引入 `theme-chalk/index.scss`(入口样式文件)和 `layout/index.vue`(入口组件)。 ``` *.vue ——> Layout/index.vue ——> index.ts <—— theme-chalk/index.scss <—— *.scss 多个功能组件 ——> 入口组件 ——> 入口运行文件 <—— 入口样式文件 <—— 多个功能组件样式 ``` ::: tip 这也就是为什么在 `.vitepress/theme/index.ts` 里单独引入 Teek 样式的原因。 ::: ## 样式结构设计 Teek 的样式结构设计遵循单一原则:每个样式文件只负责渲染单独的模块(组件),如: * `nav-var.scss` 只提供导航栏的 `css var` 变量 * `nav-search-button.scss` 只渲染导航栏的搜索按钮,内部引用了 `nav-var.scss` * `nav-switch-button.scss` 只渲染导航栏的深色、浅色切换按钮,内部引用了 `nav-var.scss` * `nav-translation.scss` 只渲染导航栏的国际化下拉框,内部引用了 `nav-var.scss` 这样的好处是,不同的样式之间是独立的,需要根据自己的需求按需引入对应的样式文件,不会存在引入一个内容超大的样式文件,导致不想要的元素也发生了样式改变。 当然,对于不喜欢折腾、研究的小伙伴来说,Teek 也提供了 `nav.scss` 样式文件,该文件内部没有编写任何样式代码,而是引入了 `nav-xxx.scss` 等样式文件,用于快速引入 `nav` 的所有样式文件。 ## 目录结构 下面给出 Teek 的样式目录结构: ```sh theme-chalk/src. ├─ base.scss # 基础样式文件 ├─ index.scss # 入口样式文件 │ ├─ common # 通用样式目录 ├─ components # 组件样式目录,对应每个 Vue 组件 ├─ md-plugin # Markdown 插件样式目录 ├─ mixins # 样式混入目录 ├─ module # 模块样式目录 ├─ var # 样式变量目录 └─ vp-plus # VitePress 样式加强目录 ``` 在 `components` 目录下,Teek 会给每个组件生成对应的样式文件,文件名与组件名相近(字母小写 + `-` 分割来命名)。 `index.scss` 文件是入口样式文件,它将导入 `base.scss`、`var` 目录下的样式文件,以及 `components` 目录下所有组件的样式文件。 如果需要按需加载组件,您必须要引入 `base.scss` 文件,这是 Teek 的核心主题样式文件,然后按需引入 Vue 组件和 `components` 目录下的对应组件的样式文件。 ## 命名空间 Teek 并没有简单的直接给一个 `div` 元素添加 `class="button"`,然后在 CSS 里 `.button {}` 定义样式,Teek 使用 **命名空间** 的设计思想,给每个组件添加唯一标识,确保不同组件的相同 `class` 发生样式冲突。 ::: tip 命名空间等价于 Vue 组件 `style` 的 `scoped` 属性。 ::: ### SCSS 定义命名空间 命名空间其实是一个唯一的前缀,如 ElementPlus 的命名空间为 `el`,在某个 `class` 中添加 `el-` 前缀,如 `
` 命名空间应该是一个变量,这样只需要修改该变量的值,那么所有的 `class` 以及样式都不会失效,如在 ElementPlus 的命名空间文件里修改 `el` 为 `tk`,那么所有的 `class` 都变为 `tk` 开头,且样式不会失效。 ::: tip Teek 的命名空间为 `tk`。 ::: 首先 Teek 在 `theme-chalk/mixins/config.scss` 文件中定义了命名空间变量 `$namespace`: ```scss $namespace: "tk" !default; ``` 此时其他的 SCSS 文件都需要引入该文件,然后使用 `$namespace` 变量: ```scss @use "../mixins/config"; .#{$namespace}-button { } ``` 当然这只是简单的 Demo,实际的使用请看 [样式文件使用 BEM](#样式文件使用-bem)。 ### JS/TS 使用命名空间 在 [定义命名空间](#定义命名空间) 中通过 `$namespace` 定义了命名空间,那么 Vue 组件里的 `template` 元素如何使用呢?总不能直接写 `
`,一旦这样,修改 `$namespace` 的值,那么所有的 `class` 都会失效,因此需要想办法直接在 `template` 使用 `$namespace` 变量。 通过 SCSS Module API 可以将 `$namespace` 变量导出到 `js` 或 `ts` 文件里,在 `theme-chalk/module/namespace.module.scss` 文件导出 `$namespace`: ```scss /* theme-chalk/module/namespace.module.scss */ @use "../mixins/config" as *; :export { namespace: #{$namespace}; } ``` ::: info SCSS Module API 只对 `.module.scss` 结尾的文件提供变量暴露功能。 ::: 如果是 Typescript 环境使用,则还需要在同级目录下定义一个 `namespace.module.scss.d.ts` 文件: ```ts // theme-chalk/module/namespace.module.scss.d.ts export interface ScssVariables { [x: string]: unknown; namespace: string; } export let variables: ScssVariables; export default variables; ``` 最后在 Vue 组件引入 `namespace.module.scss`: ```vue ``` 当然这只是简单的 Demo,实际的使用请看 [组件元素使用 BEM](#组件元素使用-bem)。 ::: tip 将 `$namespace: tk` 改为 `$namespace: xx`(xx 为你的项目名/框架名),那么没人知道它是 teek,它已经完全属于你。 ::: ## 什么是 BEM Teek 使用 BEM 规范进行样式编写,并使用 SCSS 进行样式编写。 BEM 是一种前端开发方法论,全称是 Block Element Modifier(块、元素、修饰符)。它提供了一种命名约定,用于组织和管理 CSS 类名,从而提高代码的可维护性、可扩展性和复用性。 * Block(块) * 独立的功能模块,可以独立存在 * 示例:`button`、`menu`、`input` * Element(元素) * 属于某个 Block 的一部分,不能单独存在 * 使用双下划线 `__` 连接 Block 和 Element * 示例:`menu__item`、`button__text` * Modifier(修饰符) * 用于改变 Block 或 Element 的外观或行为 * 使用双横线 `--` 表示 * 示例:`button--large`、`menu__item--active` BEM 方法的引入主要是为了解决传统 CSS 开发中常见的问题,尤其是在大型项目或团队协作中,这些问题会变得更加突出。以下是使用 BEM 的主要原因以及它解决的痛点: * 样式冲突:在传统的 CSS 开发中,类名可能会重复或不够具体,导致样式冲突。例如,多个开发者可能都定义了一个名为 `button` 的样式,但它们的行为和外观完全不同 * 可维护性差:随着项目的增长,CSS 文件变得越来越复杂,难以找到特定样式的定义位置,或者修改一个样式时意外影响到其他部分 * 样式复用困难:在没有明确规范的情况下,开发者可能需要重复编写类似的样式代码,增加了冗余 * 团队协作困难:在多人协作的项目中,不同开发者可能采用不同的命名习惯,导致代码风格不一致,难以统一管理 * 样式与结构分离不清晰:在某些情况下,开发者可能直接通过 HTML 结构(如标签选择器、后代选择器)来定义样式,这会导致样式与结构紧密耦合,难以迁移或重构 * 缺乏扩展性:当需要对现有样式进行扩展或修改时,可能会因为复杂的嵌套关系或不清晰的命名规则而感到困难 ### BEM 命名规则 * Block: `blockName` * Block + Element: `blockName__elementName` * Block + Modifier: `blockName--modifierName` * Element + Modifier: `blockName__elementName--modifierName` ```html
文字按钮 文字加粗按钮
``` ```css /* Block */ .button { /* 样式 */ } /* Element */ .button__text { /* 样式 */ } /* Modifier */ .button--large { /* 样式 */ } /* Element + Modifier */ .button__text--bold { /* 样式 */ } ``` ## 组件元素使用 BEM 定义一个 Hooks 文件 [useNamespace.ts](https://github.com/Kele-Bingtang/vitepress-theme-teek/tree/master/packages/composables/useNamespace.ts) 来封装命名空间和 BEM 规范,[命名空间](#命名空间) 和 [BEM 规范](#什么是-bem) 在上文已经介绍过了。 在组件中引入 `useNamespace.ts` 文件,使用命名空间 + BEM 规范来编写 `class`,如: ```vue ``` 等于: ```vue ``` 具体使用请看 Teek 的组件源码。 ## 样式文件使用 BEM 定义 SCSS 文件 [bem.scss](https://github.com/Kele-Bingtang/vitepress-theme-teek/tree/master/packages/theme-chalk/src/mixins/bem.scss) 来封装命名空间和 BEM 规范, 在样式文件引入 `bem.scss` 文件,使用 `bem.scss` 文件提供的 `mixins` 来编写样式,如: ```scss @use "../mixins/bem" as *; @include b("button") { @include e("text") { @include m("bold") { } } @include m("large") { } .button { @include is("primary") { } } } ``` 等于: ```scss .tk-button { .tk-button__text { &--bold { } } .tk-button--large { } .button { &.is-primary { } } } ``` 具体使用请看 Teek 的样式源码。 ## CSS Var 变量使用命名空间 Teek 给所有的 CSS Var 变量都添加命名空间,如: ```css --tk-text-color-secondary: #86909c; ``` 为了共用 `$namespace` 变量,所以 Teek 提供了 `set-css-var` Mixin 和 `getCss-Var` 函数来进行封装: ```scss /* theme-chalk/mixins/mixin.scss */ @use "./function" as *; @mixin set-css-var($name, $value) { #{joinVarName($name)}: #{$value}; } ``` ```scss /* theme-chalk/mixins/function.scss */ $namespace: "tk" !default; // 假设这里定义了命名空间 /* 合并变量名:joinVarName(('button', 'text-color')) => '--tk-button-text-color' */ @function joinVarName($list) { $name: "--" + config.$namespace; @each $item in $list { @if $item != "" { $name: $name + "-" + $item; } } @return $name; } /* getCssVar('button', 'text-color') => var(--tk-button-text-color) */ @function getCssVar($args...) { @return var(#{joinVarName($args)}); } ``` 使用 `set-css-var` 来定义 CSS Var 变量: ```scss @use "../mixins/mixins" as *; :root { @include set-css-var(button-width, 84px); @include set-css-var(button-height, 32px); @include set-css-var(button-color, #3451b2); @include set-css-var(button-font-size, 16px); } ``` 等于 ```scss :root { --tk-button-width: 84px; --tk-button-height: 32px; --tk-button-color: #3451b2; --tk-button-font-size: 16px; } ``` 使用 CSS Var 变量: ```scss @use "../mixins/function" as *; .demo { width: getCssVar(button-width); height: getCssVar(button-height); color: getCssVar(button-color); font-size: getCssVar(button-font-size); } ``` 等于 ```scss .demo { width: var(--tk-button-width); height: var(--tk-button-height); color: var(--tk-button-color); font-size: var(--tk-button-font-size); } ``` 具体使用请看 Teek 的 CSS Var 源码。 --- --- url: /20.资源/05.案例.md --- # 案例 ## 知识库兼博客案例 ::: imgCard ```yaml - img: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/vp-teek-cover/20250513215841.png link: https://vp.teek.top name: Teeker Blog desc: 朝圣的使徒,正在走向编程的至高殿堂! author: Teeker avatar: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/user/avatar1.png - img: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/vp-teek-cover/20250519232135.png link: https://onedayxyy.cn/ name: One Blog desc: "明心静性,爱自己(Tip: 博客元素多)" author: One avatar: https://onedayxyy.cn/img/xyy.webp - img: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/vp-teek-cover/20250520013439.png link: https://teek.seasir.top/ name: Hyde Blog desc: "人心中的成见是一座大山(Tip: 博客元素多)" author: Hyde avatar: https://teek.seasir.top/avatar/avatar.webp - img: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/vp-teek-cover/20250519232305.png link: https://blog.snowlinlan.com/ name: 雪鈴 Blog desc: 喵喵(? author: 雪鈴 avatar: https://blog.snowlinlan.com/logo.png - img: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/vp-teek-cover/20250513220043.png link: https://sinc.us.kg/ name: 凿壁偷光不算偷 Blog desc: 人心中的成见是一座大山~ author: 凿壁偷光不算偷 avatar: https://sinc.us.kg/webp/70.wallpaper/卡通头像.webp - img: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/vp-teek-cover/20250810162843.png link: https://dl-web.top/ name: 威威 desc: 人心中的成见是一座大山~ author: 威威 avatar: https://dl-web.top/avatar/avatar.webp - img: https://static.jokerbai.com/blog/2025/08/12/fa6ee71de3117ce39f0a9fd79f5f2ec8_MD5.jpeg link: https://jokerbai.com/ name: 乔克视界 desc: 云原生爱好者 author: 乔克 avatar: https://jokerbai.com/img/logo.png - img: https://www.kdaiyu.com/images/blog-cms.png link: https://www.kdaiyu.com/ name: 泊远的博客 desc: 泊远的技术博客,包括Java、前端、Python、AI 等技术开发经验分享。 author: 泊远 avatar: https://foruda.gitee.com/avatar/1676896264024578536/16796_poter_1578915118.png - img: https://image.peterjxl.com/blog/blog-Screenshot-2026-2-19.png link: https://www.peterjxl.com name: 晓林的博客 desc: 从 01 开始 author: 晓林 avatar: https://image.peterjxl.com/blog/re0.jpg - img: https://s3api.srebro.cn:443/picgo/202512101234994.webp link: https://opforge.srebro.cn/ name: opforge 运维知识库 desc: 运维锻造,知识沉淀。 author: srebro | 运维小弟 avatar: https://opforge.srebro.cn/logo.png ``` ::: ## 文档站案例 ::: imgCard ```yaml - img: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/teek-design/20250807012638.png link: https://vue3-design-docs.teek.top/ name: Teek Design Vue3 desc: 一个颜值强大、功能丰富、开箱即用的中后台管理系统解决方案 author: Teeker avatar: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/user/avatar1.png - img: https://vp.teek.top/blog/bg2.webp link: https://security.teek.top/ name: Hd Security desc: 一个轻量级、易用性高、拓展强的权限认证框架 author: Teeker avatar: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/user/avatar1.png - img: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/vp-teek-cover/20250522213028.png link: https://docs.dot520.net name: Netshare desc: C#全栈知识体系 author: Netshare avatar: https://docs.dot520.net/csharplogo.svg - img: https://jenkinsguide.opsre.top/ghimgs/other/home.webp link: https://jenkinsguide.opsre.top/ name: JenkinsGuide desc: 以其渺小,构建伟大 author: 二丫讲梵 avatar: https://jenkinsguide.opsre.top/ghimgs/other/avatar.jpeg - img: https://down.cxcare.top/kandu.png link: https://kandu.cxcare.top name: KylinOS/UOS技术文档 desc: 干货满满的技术笔记 author: 时光 avatar: https://down.cxcare.top/avatar.jpg - img: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/vp-teek-cover/20250824222650.png link: https://docs.frigate-cn.video name: Frigate中文文档 desc: Frigate中文社区维护的中文文档 author: Frigate-CN avatar: https://docs.frigate-cn.video/img/logo.svg - img: https://76.nansin.top/articlePicture/articlePicture-20260509173933878_image.png link: https://www.nansin.top/ name: 南生论坛 desc: 一个轻量、简洁、大厂架构、跨平台、性能高效的商业级社区系统 author: 马亮南生 avatar: https://76.nansin.top/headPortrait/headPortrait-20250311235538252_head.png ``` ::: ## 申请加入案例 如果您想在这个页面展示你的站点信息,请提交一个 [申请加入案例 Issue](https://github.com/Kele-Bingtang/vitepress-theme-teek/issues/new?template=join_case.yaml)。 --- --- url: /01.指南/01.简介/30.永久链接.md --- # 永久链接 ## 永久链接 VitePress 默认以 Markdown 文件路径作为链接访问,这会存在一个缺陷,当文件路径改变时,链接也会改变(再访问原来链接就会 404),在配置侧边栏、导航栏、各个文档链接引用、分享等场景时造成很大困扰。 因此需要给文件添加一个 **永久链接**,无论文件路径改变,访问链接不会改变。 Teek 使用 [vitepress-plugin-permalink](https://github.com/Kele-Bingtang/vitepress-theme-teek/blob/master/plugins/vitepress-plugin-permalink) 来实现永久链接功能。 插件已经内置到 Teek 中,你只需要在 Markdown 文件的 `frontmatter` 中添加如下内容: ```yaml --- permalink: /guide/quickstart --- ``` 这样就可以通过 `/guide/quickstart` 访问该页面了。 如果您不需要永久链接功能,请不配置 `permalink` 或者直接禁用该插件: ```ts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { permalink: false, // 禁用该插件 }, }); ``` ## 永久链接方式 `vitepress-plugin-permalink` 插件提供两种方式实现永久链接: 1. `Proxy` 方式 2. `Rewrites` 方式 `Proxy` 方式不会影响文件路径,而是在访问文件路径时,通过代理(拦截)将其转换为 `permalink`,因此既可以通过 VitePress 自带的文件路径方式访问,也可以通过 `permalink` 方式访问。其缺点在于地址栏有明显的链接转换变化。 `Rewrites` 方式在项目运行或者构建时,通过改变文件路径达到永久链接功能,即运行后里根据永久链接创建新的文件路径,但是不会影响该文件的本地路径,你可以在构建的 `dist` 文件夹查看修改后的文件路径。 两者只能二选一,如果都配置,则以 `Rewrites` 方式为主。 Teek 默认为 `Proxy` 方式,如果替换为 `Rewrites` 方式,在 `config.mts` 里添加如下代码: ```ts import { defineConfig } from "vitepress"; import { createRewrites } from "vitepress-theme-teek/config"; export default defineConfig({ rewrites: createRewrites(/** options */), }); ``` `createRewrites` 函数支持除了传入 `vitepress-plugin-permalink` 的 [配置项](https://github.com/Kele-Bingtang/vitepress-theme-teek/blob/master/plugins/vitepress-plugin-permalink/src/types.ts),也支持额外传入两个配置项: * `srcDir`:VitePress 的 [srcDir](https://vitepress.dev/zh/reference/site-config#srcdir),默认为 `.`,即当前项目的绝对目录 * `locales`:VitePress 的 [locales](https://vitepress.dev/zh/guide/i18n#internationalization) 如果没有传入配置项,则默认为从文档的根目录进行扫描。 ## 侧边栏方式 Teek 使用 [vitepress-plugin-sidebar-resolve](https://github.com/Kele-Bingtang/vitepress-theme-teek/blob/master/plugins/vitepress-plugin-sidebar-resolve) 来实现自动生成侧边栏功能。 默认情况下,Teek 按照项目的目录结构生成侧边栏(对应 `Proxy` 的永久链接模式),如果你修改永久链接方式为 `Rewrites`,则目录结构作为侧边栏将会失效,因此需要手动开启 `rewrites` 生成侧边栏规则。 通过 `resolveRule` 配置项来配置侧边栏生成规则: * 当 `resolveRule` 为 `filePath`,则按照本地文件路径生成侧边栏,对应 `Proxy` 的永久链接模式 * 当 `resolveRule` 为 `rewrites`,则按照 `rewrites` 结果生成侧边栏,对应 `Rewrites` 的永久链接模式 ```ts import { defineConfig } from "vitepress"; import { createRewrites } from "vitepress-theme-teek/config"; export default defineConfig({ rewrites: createRewrites(), vite: { plugins: [ sidebarOption({ resolveRule: "rewrites", }), ], }, }); ``` 如果 `resolveRule` 为 `rewrites`,但是没有 `rewrites` 配置,则按照 `filePath` 配置生成侧边栏。 ## 什么是 rewrites `rewrites` 是什么?,官方介绍请看 VitePress 的 [路由重写](https://vitepress.dev/zh/guide/routing#route-rewrites) 描述。 这里简单说下个人理解,`filePath` 称之为 **本地文件路径**,`rewrites` 称之为 **运行文件路径**。 本地文件路径通俗易懂,那什么是运行文件路径? 我们访问的 VitePress 文档的链接地址就是 **运行文件路径**。VitePress 启动后,默认会将本地文件路径当作运行文件路径,但是我们可以通过 `rewrites` 将本地文件路径重写为新的文件路径,新的文件路径就会取代本地文件路径成为运行文件路径。 假设文件 `quick-start.md` 在本地路径为 `guide/quick-start.md`,在 `rewrites` 中添加如下配置: ```ts import { defineConfig } from "vitepress"; export default defineConfig({ rewrites: { "guide/quick-start.md": "/config/quick.md", }, }); ``` 此时该文件的运行文件路径(访问链接)为 `/config/quick` 而不是 `/guide/quick-start`。 --- --- url: /15.主题开发/20.目录结构.md --- # 目录结构 Teek 的目录结构如下: ```sh packages. ├─ components # 组件目录,具体内容请看「组件布局的目录结构」 ├─ config # 配置文件目录,在 `.vitepress/config.mts` 文件中引入 ├─ helper # 工具类目录 ├─ composables # composables 目录 ├─ locale # 国际化文件目录 ├─ markdown # markdown 插件目录 ├─ static # 静态资源目录 ├─ teek # Teek 入口文件 ├─ theme-chalk # 样式目录,具体内容请看「样式布局的样式目录」 ``` `helper` 目录结构如下: ```sh helper. | ├─ analytics | | ├─ baiduAnalytics.ts # 百度统计函数 | | ├─ googleAnalytics.ts # 谷歌统计函数 | | ├─ umamiAnalytics.ts # umami 统计函数 ├─ color.ts # 颜色计算函数 ├─ date.ts # 日期格式化函数 ├─ index.ts # 工具函数入口文件,导出了所有的工具函数 ├─ is.ts # 判断类型函数,如 isString、isFunction 等 ├─ types.ts # 常用的 TS 类型 ├─ util.ts # 基础工具函数 ``` `composables` 目录结构如下: ```sh composables. ├─ index.ts # composables 入口文件,导出了所有的 composables 函数 ├─ onClickOutside.ts # 监听鼠标点击外部元素函数 ├─ useAnchorScroll.ts # 锚点滚动函数 ├─ useUvPv.ts # 访问量统计函数 ├─ useClipboard.ts # 文本复制函数 ├─ useDebounce.ts # 防抖函数 ├─ useElementHover.ts # 监听鼠标悬停指定元素函数 ├─ useEventListener.ts # 使用事件监听函数 ├─ useLocale.ts # 多语言读取函数 ├─ useMediaQuery.ts # 媒体查询函数,常用于获取 max-width、min-width 来判断是否为移动端 ├─ useMounted.ts # 监听元素全部挂载完成函数,使用了 Vue 的 onMounted 生命周期 ├─ useNamespace.ts # 命名空间函数,具体使用请看「样式布局的组件元素使用 BEM」 ├─ usePopoverSize.ts # 计算 Popover 出现的位置 ├─ useScopeDispose.ts # 父作用域销毁函数,概念等于 Vue 的 onUnmounted 生命周期 ├─ useScrollData.ts # 数据滚动函数,用于友情链接卡片自动向下滚动 ├─ useStorage.ts # 管理存储的函数,根据传入的存储类型(sessionStorage 或 localStorage)返回相应的操作函数 ├─ useSwitchData.ts # 数据定时切换函数,用于 Body、Banner 的图片切换 ├─ useTextTypes.ts # 文本打印函数,用于 Banner 的详细描述打印效果 ├─ useThemeColor.ts # 主题色计算函数,自动根据主题色计算其他的颜色 ├─ useViewTransition.ts # 切换动画效果函数,用于深色、浅色模式切换 ├─ useVpRouter.ts # 绑定自定义函数到 Router 的钩子里,为了防止覆盖掉其他人已添加在 Router 钩子的逻辑,useVpRouter 不是直接覆盖,而是追加 ├─ useWindowSize.ts # 窗口大小监听函数,用于实时监听窗口的 width、height ├─ useZIndex.ts # z-index 管理函数 ``` * `components` 的目录结构请看 [组件目录结构](/develop/components#目录结构) * `theme-chalk` 的目录结构请看 [样式目录结构](/develop/styles#目录结构)。 其他目录结构内容较少,从命名可以看出效果,因此暂不进行详细说明。 --- --- url: /10.配置/20.目录页配置.md --- # 目录页配置 什么是目录页?可以在本文章最上方的面包屑里点击 配置 查看效果。 ::: warning 目录页数据来源于 `vitepress-plugin-catalogue` 插件实现,如果禁用了该插件,目录页将不会生效。 ::: 目录页本质上是一个 Markdown 文档,因此可以与其他文档一起放到任意目录下,如: ::: code-group ```sh [当前文件夹] {4,10,15} . │ ├─ 01.指南 │ │ 00.目录.md │ ├─ 01.指南 - 使用 │ │ │ 00.目录.md │ │ ├── 04.使用 - 登录认证.md │ │ ├── 07.使用 - 权限认证.md │ ├─ 05.指南 - 环境集成 │ │ │ 00.目录.md │ │ ├── 04.环境集成 - Spring Boot.md │ │ ├── 07.环境集成 - Spring WebFlux.md │ │ ├── 99.环境集成 - 上下文组件开发指南.md ├─ 05.设计 │ │ 00.目录.md │ ├─ 01.设计 - 思路 │ │ │ 01.设计 - 思路设计.md │ ├─ 03.设计 - Helpers │ │ ├── 01.设计 - Helpers 说明.md ``` ```sh [专门创建目录页文件夹] {3-7} . │ ├─ 00.目录页 │ │ 01.指南 - 目录.md │ │ 05.使用 - 目录.md │ │ 10.环境集成 - 目录.md │ │ 15.设计 - 目录.md ├─ 01.指南 │ ├─ 01.指南 - 使用 │ │ ├── 04.使用 - 登录认证.md │ │ ├── 07.使用 - 权限认证.md │ ├─ 05.指南 - 环境集成 │ │ ├── 04.环境集成 - Spring Boot.md │ │ ├── 07.环境集成 - Spring WebFlux.md │ │ ├── 99.环境集成 - 上下文组件开发指南.md ├─ 05.设计 │ ├─ 01.设计 - 思路 │ │ │ 01.设计 - 思路设计.md │ ├─ 03.设计 - Helpers │ │ ├── 01.设计 - Helpers 说明.md ``` ::: 有两种方式可以开启目录页: 1. 在 `frontmatter` 配置 `catalogue: true` 和 `layout: page` 来开启目录页 2. 在 `frontmatter` 配置 `catalogue: true` 和 `layout: TkCataloguePage` 来开启目录页 目录页的 `frontmatter` 配置如下: ::: code-group ```yaml [方式 1] --- catalogue: true layout: page path: 05.设计 desc: Hd Security 设计思路 pageTitle: 设计体系目录 sidebar: false article: false --- ``` ```yaml [方式 1 带注释] --- catalogue: true # 目录页(必填) layout: page # page 布局(必填) path: 05.设计 # 设置为根目录下的某个文件夹相对路径(必填) desc: Hd Security 设计思路 # 目录描述 pageTitle: 设计体系目录 # 页面标题,默认为目录 sidebar: false # 不显示侧边栏 article: false # 不显示在首页的文章列表和归档页 --- ``` ```yaml [方式 2] --- catalogue: true layout: TkCataloguePage path: 05.设计 desc: Hd Security 设计思路 pageTitle: 设计体系目录 sidebar: false article: false --- ``` ```yaml [方式 2 带注释] --- catalogue: true # 目录页(必填) layout: TkCataloguePage # TkCataloguePage 布局(必填) path: 05.设计 # 设置为根目录下的某个文件夹相对路径(必填) desc: Hd Security 设计思路 # 目录描述 pageTitle: 设计体系目录 # 页面标题,默认为目录 sidebar: false # 不显示侧边栏 article: false # 不显示在首页的文章列表和归档页 --- ``` ::: ::: tip 配置好目录页之后,点击文章页的面包屑将会跳转到目录页。 当然,您也可以在导航栏里添加目录页的链接,例如:`permalink: /design/` ::: --- --- url: /01.指南/10.使用/45.私密文章.md --- # 私密文章 私密文章需要一个登录页进行登录,如果你想先体验登录页的效果,在导航栏 功能页 -> 登录页 点击查看。 您也可以通过 `teek-login-page` 插槽自定义登录页。 ```vue ``` ## 前言 私密文章功能默认没有和后端集成,因此只能 **防君子不防小人**。 当然 Teek 也提供了一些钩子函数,支持您自定义登录逻辑和加密解密,此时您可以全部重写 Teek 的登录逻辑,比如集成后端。 当然如果全部重写登录逻辑,那么就要思考一个问题:为什么不完全自己写一个呢?毕竟去完全熟悉 Teek 的登录逻辑也许比自己实现耗费的精力更多 :dog:。 ## 安全检测代码 因为 VitePress 是静态页面,所以我们无法往后端获取登录信息,那么也就有一个问题,如果用户禁用 JavaScript,那么私密文章将不会进行验证,也就可以直接浏览私密文章内容,那么如何处理这个问题呢? 打开 `.vitepress/config.mts` 文件,给 head 模块添加如下信息: ```js ["noscript", {}, '']; ``` `{your link}` 不要填写自己博客的任意地址,而是填写博客以外的地址,因为博客的页面总会触发这段代码,导致反复跳转该页面。 ## 开启私密文章认证功能 这一步是必须的,请阅读 [功能页配置](/reference/function-page-config#私密文章-登录页) 来开启私密文章认证功能。 ## 文章开启私密功能 如果你想给某篇文章开启私密功能,请在 `frontmatter` 中添加如下内容: ```yml --- private: true --- ``` 这是 **最基本也是必须的步骤**,开启了私密文章后,还需要配置对应的用户名和密码,看下面。 ## 认证级别 私密文章认证有 4 种级别: 1. 单文章级别,每个文章有自己的用户名和密码 2. 领域文章级别,可以给多个文章设置一个领域(组织),在该领域认证后,则该领域的其他所有文章都可以访问,它是一个组织的概念,理解就行 3. 全局文章级别,在任意全局文章登录认证后,其他全局文章都可以访问 4. 站点级别,在进入站点的时候需要进行认证,该级别和私密文章认证没有关系 如果同时设置多个文章级别的认证信息,那么有如下规则: * 一个文章同时设置 `单文章级别认证信息`、`领域文章级别认证信息`,则这两个级别的认证信息都对该文章 **生效** * 一个文章同时设置 `单文章级别认证信息`、`全局文章级别认证信息`,则 `全局文章级别认证信息` 对该文章 **失效** * 一个文章同时设置 `领域文章级别认证信息`、`全局文章级别认证信息`,则 `全局文章级别认证信息` 对该文章 **失效** * 一个文章同时设置 `单文章级别认证信息`、`领域文章级别认证信息`、`全局文章级别认证信息`,则 `全局文章级别认证信息` 对该文章 **失效**,另外两个认证信息都对该文章 **生效** 从上面可以看出,`全局文章级别认证信息` 优先级是最低的,是一个兜底的配置。 站点级别认证有一个角色的概念,默认为 `common`,即当进入站点并登录认证后,访问任何私密文章仍然需要重新进行认证,而如果是 `admin` 角色,则进入站点后,所有文章都可以访问。 ### 单文章级别 在某个私密文章的 `frontmatter` 中设置用户名和密码等配置: ```yml --- private: true # 开启文章私密 username: teek # 用户名 password: teek # 密码 expire: 2d # 可选,登录失效时间,如果不填则以全局配置为准,全局设置默认为 1d session: false # 可选,开启是否在网页关闭或刷新后,清除登录状态,这样再次访问网页,需要重新登录,默认为 false strategy: once # 可选,登录策略,once 代表一次登录,always 代表每次访问都登录,默认为 once loginInfo: [{ username: "teek1", password: "teek1" }, { username: "teek2", password: "teek2" }] --- ``` ::: warning `username` 或 `password` 不允许是纯数字,如果您只想配置纯数字,则用引号起来,如 `"1234"`、`'1234'`。 ::: 可以看到 `frontmatter` 出现了 `username`、`password`,并且 `loginInfo` 里也出现多个 `username`、`password`。 这两种方式没有什么区别,无论是以 `username`、`password` 登录,还是 `loginInfo` 里的多个 `username`、`password` 都可以登录。 ### 领域文章级别 有的时候,我们并不需要给每一个文章设置用户名和密码,而是按「组」的概念设置。 比如我们有 `指南` 和 `配置` 两个专题的文章,那么我可以对这两个专题进行认证,在 `.vitepress/config.mts` 文件配置如下: ```ts // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ private: { enabled: true, realm: { guide: [ { username: "teek-guide-1", password: "teek" }, { username: "teek-guide-2", password: "teek" }, ], config: [ { username: "teek-config-1", password: "teek" }, { username: "teek-config-2", password: "teek" }, ], }, }, }); ``` 在 `指南` 的各个文章 `frontmatter` 配置绑定对于的 `realm`: ```yaml private: true privateRealm: guide ``` 在 `配置` 的各个文章 `frontmatter` 配置绑定对于的 `realm`: ```yaml private: true privateRealm: config ``` ### 全局文章级别 有时候我们想直接提供一些用户名和密码,它能访问页面的所有文章,那么可以使用全局文章级别配置: ```ts // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ private: { enabled: true, pages: [ { username: "tee-pages-1", password: "teek" }, { username: "tee-pages-1", password: "teek" }, ], }, }); ``` 此时可以访问 **非单文章级别、非领域文章级别** 的其他任何私密文章。 ### 站点级别 站点级别的认证主要是卡控站点的访问,而不是文章的访问。 在 `.vitepress/config.mts` 里开启站点级别认证并设置认证信息: ```ts // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ private: { enabled: true, siteLogin: true, site: [ { username: "teek-site-1", password: "teek" }, { username: "teek-site-2", password: "teek" }, ], }, }); ``` 这些用户名和密码默认是 `common` 角色,即只适用于进入站点时登录,当访问任意私密文章时,仍需单独对私密文章认证。 如果想登录站点后可以访问所有私密文章,则给账号开启 `admin` 角色进行如下配置: ```ts {11} // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ private: { enabled: true, siteLogin: true, site: [ { username: "teek-site-1", password: "teek" }, { username: "teek-site-2", password: "teek" }, { username: "teek-site-2", password: "teek", role: "admin" }, ], }, }); ``` ## 其他配置 除了用户名和密码之外,Teek 也有其他的配置项来加强私密文章功能,更多配置请阅读 [功能页配置](/reference/function-page-config#私密文章-登录页) --- --- url: /01.指南/10.使用/35.站点统计.md --- # 站点统计 Teek 集成了四种常见的站点统计工具: * 百度分析 `Baidu Analytics` * 谷歌分析 `Google Analytics` * 微软 Clarity `Microsoft Clarity` * `Umami` 分析 让你可以轻松地在 VitePress 网站中集成并管理这些分析工具。无论是微软 `Clarity` 、谷歌分析的强大功能,还是百度统计对中国市场的适配,或者是 `Umami` 的隐私友好型方案,都可以通过这个插件快速集成并使用。 ## 百度统计 ```ts // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ siteAnalytics: [ { provider: "baidu", options: { id: "******", }, }, ], }); ``` ### 获取 Baidu Analytics ID 1. 访问 [百度统计](https://tongji.baidu.com/) 网站 2. 使用百度账号登录或注册一个新账号 3. 登录后,点击页面上方的 `我的报告`-`使用设置`-`网站列表` 4. 输入你的网站 URL,选择适当的分类,然后点击 `保存` 5. 保存后,点击获取代码。会看到类似于 `https://hm.baidu.com/hm.js?******` 的内容 6. 复制链接中`******`部分 **参考链接:** [百度统计官方文档](https://tongji.baidu.com/web/help/article?id=175\&type=0) ## 谷歌分析 ```ts // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ siteAnalytics: [ { provider: "google", options: { id: "******", }, }, ], }); ``` ### 获取 Google Analytics ID 1. 访问 [Google Analytics](https://analytics.google.com/) 网站 2. 登录到你的 Google Analytics 帐号 3. 创建一个新的 Google Analytics 账户,或者选择已有的账户 4. 在左下角点击 `Admin`(管理) 5. 在 `Account`(账户)列下,选择你的账户 6. 在 `Property`(属性)列下,选择你的站点,或者创建一个新的站点 7. 在 `Property Settings`(属性设置)中,找到 `Tracking Info`(跟踪信息) 8. 点击 `Tracking Code`(跟踪代码),你会看到类似 `G-XXXXXXX` 的 ID **参考链接:**[Google Analytics 帮助文档](https://support.google.com/analytics/answer/9304153?hl=zh-Hans) ## 微软 Clarity ```ts // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ siteAnalytics: [ { provider: "clarity", options: { id: "******", }, }, ], }); ``` ### 获取 Microsoft Clarity ID 1. 访问 [Microsoft Clarity](https://clarity.microsoft.com/) 网站 2. 登录到你的 Microsoft Clarity 帐号 3. 创建一个新的 Microsoft Clarity 账户,或者选择已有的账户 4. 选择你的项目,或者创建一个新的项目 5. 在 `设置` 页面的 `概览` 中,找到 `项目 ID` ## Umami ```ts // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ siteAnalytics: [ { provider: "umami", options: { id: "******", src: "https://******", }, }, ], }); ``` ### 获取 Umami Analytics ID #### 自建 Umami 1. 首先,你需要搭建 Umami 服务器。你可以参考 [Umami 文档](https://umami.is/docs/guides/hosting) 来进行安装 2. 在你搭建好的 Umami 实例中,登录到 Umami 仪表盘 3. 创建一个新的站点,并为其生成一个站点 ID 4. 获取该站点的 ID 后,就可以在你的网站代码中使用它进行跟踪 #### 使用公共 Umami 服务 1. 你也可以使用公共的 Umami 服务提供商。例如,Umami 提供了一些第三方的 Umami 实例,允许用户直接使用。 2. 获取到公共实例的 Umami ID 后,可以直接在代码中配置使用。 你的 Umami ID 应该类似于:`123abc456def`。 **参考链接:** * [Umami 文档](https://umami.is/docs/guides/hosting) * [Umami 公共服务](https://umami.is/) ## 多个站点统计 你可以配置多个站点统计,只要在 `siteAnalytics` 数组中添加多个对象即可。 ```ts // .vitepress/config.mts const teekConfig = defineTeekConfig({ siteAnalytics: [ { provider: "baidu", options: { id: "******", }, }, { provider: "google", options: { id: "******", }, }, ], }); ``` --- --- url: /01.指南/20.相关/15.笔记技巧.md --- # 笔记技巧 ::: note 摘要 为了让读者阅读时,不处于大片黑白的世界里,我们需要掌握更多丰富的笔记表现力:smile\_cat: ::: right 2025-03-31 @Teek ::: ## 使用 emoji 表情 阅读大片大片的文字难免产生视觉疲劳,而使用 emoji 表情,不仅缓解精神的渐眠,也会胜过千言。 在 markdown 里,使用 `:表情:` 输入表情,如 ```md 你好:smile:,我喜欢:dog:,我小时候经常拿:100:分哦~~~,欢迎来到我的博客:heart:,一起学习吧:muscle: ``` 效果如下: > 你好:smile:,我喜欢:dog:,我小时候经常拿:100:分哦~~~,欢迎来到我的博客:heart:,一起学习吧:muscle: 很多指令肯定是记不了的,我们可以也可以去特定的网站获取表情的格式。也可以 copy 一个表情过来,markdown 会自动解析表情。 分享一些 emoji 网站: * [Markdown 所有支持的 emoji 列表](https://github.com/markdown-it/markdown-it-emoji/blob/master/lib/data/full.mjs) * [emoji 表情备忘录](https://www.webfx.com/tools/emoji-cheat-sheet):有很多表情的格式 * [emoji 表情](https://emojipedia.org/):有很多表情可以 copy * [gitmoji](https://github.com/carloscuesta/gitmoji) 通过 emoji 表达 git 的操作内容 > windows 系统下按 Win + . 快速打开表情选择框(不是右侧小键盘的 .) ## 外部链接 使用外部链接,文字会变色,并且可以点击跳转,格式如下: ``` [Teek 官网](https://vp.teek.top) ``` 效果: [Teek 官网](https://vp.teek.top) ## 文本高亮 使用 `` 标签或者 ` `` ` 让文本高亮。 `` 标签可用于文字的突出,如果是一段字符,则使用 ` `` ` 包裹起来。 ```md `Teek` 是一款 轻量 & 简洁高效 & 灵活配置的 VitePress 主题。 ``` `Teek` 是一款 轻量 & 简洁高效 & 灵活配置的 VitePress 主题。 ## 内置徽章 输入: ```md #### 《沁园春·雪》 北国风光,千里冰封,万里雪飘。 > : 北方的风光。 ``` * text:显示的文本 * type:`info` | `tip` | `warning` | `danger`,默认是 `tip` 输出: #### 《沁园春·雪》 北国风光,千里冰封,万里雪飘。 > : 北方的风光。 ## 外置徽章 如果想用更多的自定义徽章,可使用 [Shields](https://shields.io/)来生成 ```md ![stars](https://img.shields.io/github/stars/Kele-Bingtang/vitepress-theme-teek) ![Teek badge](https://img.shields.io/npm/v/vitepress-theme-teek.svg?style=flat-square) ![kbt](https://img.shields.io/badge/teek-天客-green) ``` ![Star](https://img.shields.io/github/stars/Kele-Bingtang/vitepress-theme-teek) ![NPM Download](https://img.shields.io/npm/v/vitepress-theme-teek.svg?style=flat-square) ![Teek](https://img.shields.io/badge/Teek-天客-green) 想了解更多 Shields 的使用,请访问 [Shields](https://shields.io/)。 ## TODO 待办列表 输出: * \[ ] 吃饭 * \[ ] 睡觉 * \[x] 打豆豆 输入: ```markdown - [ ] 吃饭 - [ ] 睡觉 - [x] 打豆豆 ``` 确保 `[ ]` 里有一个空格。 ::: tip 支持所有列表语法,如:`1.`、`-`、`+`、`*` 等。 ::: ## 分享卡片列表 分享卡片列表容器,可用于 `友情链接`、`项目推荐`、`诗词展示` 等。 输入: ````yml ::: shareCard ```yaml - name: George Chan desc: 让我给你讲讲他的传奇故事吧 avatar: https://z3.ax1x.com/2021/09/30/4oKMVI.jpg link: https://cyc0819.top/ bgColor: '#FFB6C1' # 可选,默认 var(--bodyBg)。颜色值有 # 号时请添加单引号 textColor: '#621529' # 可选,默认 var(--textColor) - name: butcher2000 desc: 即使再小的帆,也能远航 avatar: https://gcore.jsdelivr.net/gh/Kele-Bingtang/static/user/20211029181901.png link: https://blog.csdn.net/weixin_46827107 bgColor: '#CBEAFA' textColor: '#6854A1' - name: Evan's blog desc: 前端的小学生 avatar: https://gcore.jsdelivr.net/gh/xugaoyi/image_store@master/blog/20200103123203.jpg link: https://xugaoyi.com/ bgColor: '#B9D59C' textColor: '#3B551F' ``` ::: ```` 输出: ::: shareCard ```yaml - name: George Chan desc: 让我给你讲讲他的传奇故事吧 avatar: https://z3.ax1x.com/2021/09/30/4oKMVI.jpg link: https://cyc0819.top/ bgColor: "#FFB6C1" # 可选,默认 var(--bodyBg)。颜色值有 # 号时请添加单引号 textColor: "#621529" # 可选,默认 var(--textColor) - name: butcher2000 desc: 即使再小的帆,也能远航 avatar: https://gcore.jsdelivr.net/gh/Kele-Bingtang/static/user/20211029181901.png link: https://blog.csdn.net/weixin_46827107 bgColor: "#CBEAFA" textColor: "#6854A1" - name: Evan's blog desc: 前端的小学生 avatar: https://gcore.jsdelivr.net/gh/xugaoyi/image_store@master/blog/20200103123203.jpg link: https://xugaoyi.com/ bgColor: "#B9D59C" textColor: "#3B551F" ``` ::: 不指定颜色,默认为白色,如下演示: ````yml ::: shareCard ```yaml - name: 《静夜思》 desc: 床前明月光,疑是地上霜。举头望明月,低头思故乡。 bgColor: '#395AE3' textColor: '#242A38' - name: Teek desc: ✨一个轻量、简洁高效、灵活配置的 VitePress 主题 link: https://github.com/Kele-Bingtang/vitepress-theme-teek bgColor: '#DFEEE7' textColor: '#2A3344' ``` ::: ```` ::: shareCard ```yaml - name: 《静夜思》 desc: 床前明月光,疑是地上霜。举头望明月,低头思故乡。 - name: Teek desc: ✨一个轻量、简洁高效、灵活配置的 VitePress 主题 link: https://github.com/Kele-Bingtang/vitepress-theme-teek bgColor: "#DFEEE7" textColor: "#2A3344" ``` ::: ## 图文卡片列表 图文卡片列表容器,可用于 `项目展示`、`产品展示` 等。 输入: ````yaml ::: imgCard ```yaml - img: https://vp.teek.top/blog/bg1.webp link: https://vp.teek.top name: 标题 desc: 描述内容描述内容描述内容描述内容 author: Teek avatar: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/user/avatar1.png - img: https://vp.teek.top/blog/bg2.webp link: https://vp.teek.top name: 标题 desc: 描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容 author: Teek avatar: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/user/avatar1.png - img: https://vp.teek.top/blog/bg2.webp link: https://vp.teek.top name: 标题 desc: 描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容 author: Teek avatar: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/user/avatar1.png - img: https://vp.teek.top/blog/bg3.webp link: https://vp.teek.top name: 标题 desc: 描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容 ``` ::: ```` 输出: ::: imgCard ```yaml - img: https://vp.teek.top/blog/bg1.webp link: https://vp.teek.top name: 标题 desc: 描述内容描述内容描述内容描述内容 author: Teek avatar: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/user/avatar1.png - img: https://vp.teek.top/blog/bg2.webp link: https://vp.teek.top name: 标题 desc: 描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容 author: Teek avatar: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/user/avatar1.png - img: https://vp.teek.top/blog/bg2.webp link: https://vp.teek.top name: 标题 desc: 描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容 author: Teek avatar: https://testingcf.jsdelivr.net/gh/Kele-Bingtang/static/user/avatar1.png - img: https://vp.teek.top/blog/bg3.webp link: https://vp.teek.top name: 标题 desc: 描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容描述内容 ``` ::: ## 导航卡片 导航卡片容器,可以用于制作 `导航站点`。 输入: ````yaml ::: navCard ```yaml - name: 百度 desc: 百度——全球最大的中文搜索引擎及最大的中文网站,全球领先的人工智能公司 link: http://www.baidu.com/ img: https://www.baidu.com/favicon.ico badge: 搜索引擎 - name: Google desc: 全球最大的搜索引擎公司 link: http://www.google.com/ img: https://ts1.cn.mm.bing.net/th/id/R-C.58c0f536ec073452434270fb559c3f8c?rik=SnOUNtUtPLX6ww&riu=http%3a%2f%2fwww.sz4a.cn%2fPublic%2fUploads%2fimage%2f20230303%2f1677839482835474.png&ehk=J1lqoeszPGEWzDOSZQ3JxzXsklfd0QzgrJu6ZVvESKk%3d&risl=&pid=ImgRaw&r=0 badge: 搜索引擎 badgeType: tip ``` ::: ```` 输出: ::: navCard ```yaml - name: 百度 desc: 百度——全球最大的中文搜索引擎及最大的中文网站,全球领先的人工智能公司 link: http://www.baidu.com/ img: https://www.baidu.com/favicon.ico badge: 搜索引擎 - name: Google desc: 全球最大的搜索引擎公司 link: http://www.google.com/ img: https://ts1.cn.mm.bing.net/th/id/R-C.58c0f536ec073452434270fb559c3f8c?rik=SnOUNtUtPLX6ww&riu=http%3a%2f%2fwww.sz4a.cn%2fPublic%2fUploads%2fimage%2f20230303%2f1677839482835474.png&ehk=J1lqoeszPGEWzDOSZQ3JxzXsklfd0QzgrJu6ZVvESKk%3d&risl=&pid=ImgRaw&r=0 badge: 搜索引擎 badgeType: tip ``` ::: ## Demo 容器 Demo 容器用于展示编写的 Vue 组件输出,且支持查看源代码、复制源代码、去 `Github` 编辑、去 `Playground` 编辑功能: 输出: ::: demo demo/button-primary ::: 输入: ```markdown ::: demo demo/button-primary ::: ``` Demo 容器默认在项目根目录的 `examples` 目录下寻找组件,如指定 `demo/button-primary` 路径,则目录结构应该如下: ```sh . ├─ .vitepress # 默认基于 vitepress(项目根目录)层级下的 examples 目录扫描 ├─ examples │ ├─ demo │ │ ├─ button-primary.vue ``` ## 自定义容器 自定义容器可以通过它们的类型、标题和内容来定义。 ### 默认标题 输入: ```md ::: note This is an note box. ::: ::: info This is an info box. ::: ::: tip This is a tip. ::: ::: warning This is a warning. ::: ::: danger This is a dangerous warning. ::: ::: details This is a details block. ::: ::: center Markdown 拓展 ::: ::: tip 摘要 很久之前,我决定踏上的这条路,映照了我与未来的因果。 ::: right 2021-11-13 @Teek ::: ``` 输出: ::: note This is an note box. ::: ::: info This is an info box. ::: ::: tip This is a tip. ::: ::: warning This is a warning. ::: ::: danger This is a dangerous warning. ::: ::: details ```ts This is a details block. ``` ::: ::: center Markdown 拓展 ::: ::: tip 摘要 很久之前,我决定踏上的这条路,映照了我与未来的因果。 ::: right 2021-11-13 @Teek ::: ### 自定义标题 可以通过在容器的 `type` 之后附加文本来设置自定义标题。 输入: ````md ::: danger STOP 危险区域,请勿继续 ::: ::: details 点我查看代码 ```js console.log("Hello, VitePress!"); ``` ::: ```` 输出: ::: danger STOP 危险区域,请勿继续 ::: ::: details 点我查看代码 ```js console.log("Hello, Teek!"); ``` ::: ## GitHub 风格的警报 VitePress 同样支持以标注的方式渲染 [GitHub 风格的警报](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts)。 ```md > [!NOTE] > 强调用户在快速浏览文档时也不应忽略的重要信息。 > [!TIP] > 有助于用户更顺利达成目标的建议性信息。 > [!IMPORTANT] > 对用户达成目标至关重要的信息。 > [!WARNING] > 因为可能存在风险,所以需要用户立即关注的关键内容。 > [!CAUTION] > 行为可能带来的负面影响。 ``` > \[!NOTE] > 强调用户在快速浏览文档时也不应忽略的重要信息。 > \[!TIP] > 有助于用户更顺利达成目标的建议性信息。 > \[!IMPORTANT] > 对用户达成目标至关重要的信息。 > \[!WARNING] > 因为可能存在风险,所以需要用户立即关注的关键内容。 > \[!CAUTION] > 行为可能带来的负面影响。 ## 自定义锚点 要为标题指定自定义锚点而不是使用自动生成的锚点,请向标题添加后缀: ``` # 使用自定义锚点 {#my-anchor} ``` 这允许将标题链接为 `#my-anchor`,而不是默认的 `#使用自定义锚点`。 ## GitHub 风格的表格 输入: ``` | Tables | Are | Cool | | ------------- | :-----------: | ----: | | col 3 is | right-aligned | $1600 | | col 2 is | centered | $12 | | zebra stripes | are neat | $1 | ``` 输出: | Tables | Are | Cool | | ------------- | :-----------: | -----: | | col 3 is | right-aligned | $1600 | | col 2 is | centered | $12 | | zebra stripes | are neat | $1 | ## 目录表 (TOC) 输入: ``` [[toc]] ``` 输出: \[\[toc]] 可以使用 `markdown.toc` 选项配置 TOC 的呈现效果。 ## 代码块中的语法高亮 VitePress 使用 [Shiki](https://github.com/shikijs/shiki) 在 Markdown 代码块中使用彩色文本实现语法高亮。Shiki 支持多种编程语言。需要做的就是将有效的语言别名附加到代码块的开头: 输入: ```` ```js export default { name: 'MyComponent', // ... } ``` ```` ```` ```html
  • {{ todo.text }}
``` ```` 输出: ```js export default { name: "MyComponent", // ... }; ``` ```html
  • {{ todo.text }}
``` 在 Shiki 的代码仓库中,可以找到[合法的编程语言列表](https://shiki.style/languages)。 ## 在代码块中实现行高亮 输入: ```` ```js{4} export default { data () { return { msg: 'Highlighted!' } } } ``` ```` 输出: ```js{4} export default { data () { return { msg: 'Highlighted!' } } } ``` 除了单行之外,还可以指定多个单行、多行,或两者均指定: * 多行:例如 `{5-8}`、`{3-10}`、`{10-17}` * 多个单行:例如 `{4,7,9}` * 多行与单行:例如 `{4,7-13,16,23-27,40}` 输入: ```` ```js{1,4,6-8} export default { // Highlighted data () { return { msg: `Highlighted! This line isn't highlighted, but this and the next 2 are.`, motd: 'VitePress is awesome', lorem: 'ipsum' } } } ``` ```` 输出: ```js{1,4,6-8} export default { // Highlighted data () { return { msg: `Highlighted! This line isn't highlighted, but this and the next 2 are.`, motd: 'VitePress is awesome', lorem: 'ipsum', } } } ``` 也可以使用 `// [!code highlight]` 注释实现行高亮。 输入: ```` ```js export default { data () { return { msg: 'Highlighted!' // [!!code highlight] } } } ``` ```` 输出: ```js export default { data() { return { msg: "Highlighted!", // [!code highlight] }; }, }; ``` ## 代码块中聚焦 在某一行上添加 `// [!code focus]` 注释将聚焦它并模糊代码的其他部分。 此外,可以使用 `// [!code focus:]` 定义要聚焦的行数。 输入: ```` ```js export default { data () { return { msg: 'Focused!' // [!!code focus] } } } ``` ```` 输出: ```js export default { data() { return { msg: "Focused!", // [!code focus] }; }, }; ``` ## 代码块中的颜色差异 在某一行添加 `// [!code --]` 或 `// [!code ++]` 注释将会为该行创建 diff,同时保留代码块的颜色。 输入: ```` ```js export default { data () { return { msg: 'Removed' // [!!code --] msg: 'Added' // [!!code ++] } } } ``` ```` 输出: ```js export default { data () { return { msg: 'Removed' // [!code --] msg: 'Added' // [!code ++] } } } ``` ## 高亮“错误”和“警告” 在某一行添加 `// [!code warning]` 或 `// [!code error]` 注释将会为该行相应的着色。 输入: ```` ```js export default { data () { return { msg: 'Error', // [!!code error] msg: 'Warning' // [!!code warning] } } } ``` ```` 输出: ```js export default { data() { return { msg: "Error", // [!code error] msg: "Warning", // [!code warning] }; }, }; ``` ## 行号 可以通过以下配置为每个代码块启用行号: ```js export default { markdown: { lineNumbers: true, }, }; ``` 可以在代码块中添加 `:line-numbers` / `:no-line-numbers` 标记来覆盖在配置中的设置。 还可以通过在 `:line-numbers` 之后添加 `=` 来自定义起始行号,例如 `:line-numbers=2` 表示代码块中的行号从 2 开始。 输入: ````md ```ts {1} // 默认禁用行号 const line2 = "This is line 2"; const line3 = "This is line 3"; ``` ```ts:line-numbers {1} // 启用行号 const line2 = 'This is line 2' const line3 = 'This is line 3' ``` ```ts:line-numbers=2 {1} // 行号已启用,并从 2 开始 const line3 = 'This is line 3' const line4 = 'This is line 4' ``` ```` 输出: ```ts {1} // 默认禁用行号 const line2 = "This is line 2"; const line3 = "This is line 3"; ``` ```ts:line-numbers {1} // 启用行号 const line2 = 'This is line 2' const line3 = 'This is line 3' ``` ```ts:line-numbers=2 {1} // 行号已启用,并从 2 开始 const line3 = 'This is line 3' const line4 = 'This is line 4' ``` ## 代码组 可以像这样对多个代码块进行分组: 输入: ````md ::: code-group ```js [config.js] /** * @type {import('vitepress').UserConfig} */ const config = { // ... }; export default config; ``` ```ts [config.ts] import type { UserConfig } from "vitepress"; const config: UserConfig = { // ... }; export default config; ``` ::: ```` 输出: ::: code-group ```js [config.js] /** * @type {import('vitepress').UserConfig} */ const config = { // ... }; export default config; ``` ```ts [config.ts] import type { UserConfig } from "vitepress"; const config: UserConfig = { // ... }; export default config; ``` ::: ## 图片懒加载 通过在配置文件中将 `lazyLoading` 设置为 `true`,可以为通过 markdown 添加的每张图片启用懒加载。 ```js export default { markdown: { image: { // 默认禁用;设置为 true 可为所有图片启用懒加载。 lazyLoading: true, }, }, }; ``` --- --- url: /01.指南/01.简介/01.简介.md --- # 简介 Teek 是一个轻量、简洁高效、灵活配置、易于扩展的 VitePress 主题 ✨,是在默认主题的基础上进行拓展,支持 VitePress 的所有功能、配置,完全可以零成本迁移过来。 使用 Teek 可以很方便的搭建一个结构化的知识库或博客。 ::: warning * Node.js `18.0.0` 及以上版本 * 在使用 Teek 前,要求至少会 VitePress 的基本使用和默认主题的基本配置,然后再查看本文档 * 本文档仅负责介绍 Teek 对 VitePress 默认主题的扩展部分,VitePress 自带配置请移步 [VitePress 中文文档](https://vitepress.dev/zh/) ::: ## 特性 > **知识管理** 包含三种典型的知识管理形态:结构化、碎片化、体系化。轻松打造属于你自己的知识管理平台。 > **结构化 & 体系化** 自动生成侧边栏、目录页、索引页、面包屑等,轻松构建一个结构化知识库。 > **碎片化 & 个性化** 博客功能提供快速构建知识的碎片化形态,并提供大量个性化的主题配置。 > **文档风 & 博客风** 支持通过配置随意切换文档风和博客风,支持个人博客、文档站、知识库等场景。 ## 拓展功能 相较于 VitePress 主题,Teek 主要实现了博客风格的功能,这些功能也兼容文档风格,您现在正在阅读的是 Teek 的文档风格。 > 全局 * 侧边栏自动生成,根据目录自动生成侧边栏,无需手动配置 * 提供目录页,根据 `Markdown` 文件路径自动生成目录 * 自动生成 `frontmatter`,并且支持拓展 `frontmatter` 格式 * 自动生成一级标题 * 全站背景图片 * `Markdown` 拓展:居中、居右容器、卡片容器、`Demo` 容器、`TODO` 列表、`Video` 容器 * 主题多元化:4 种布局模式、8 种主题风格选择,且支持自定义扩展新的主题风格 * 移动端适配:自动适配移动端 * ... > 首页 * `Banner` 功能:提供 3 种风格选择:局部背景色、局部图片、全屏图片,提供打印个性签名、切换个性签名选择,提供 `Feature` 功能 * 文章列表:支持切换列表和卡片模式,展示文章标题、封面图、作者、创建时间、更新时间、标签、分类,且支持重写文章列表 * 博客卡片栏:博主信息栏、精选文章栏、分类栏、标签栏、友情链接栏、站点信息栏 * 全屏壁纸模式:只保留 `Banner` 背景图片或全站背景图片,且禁止滚动、打开开发者工具、右键功能 * 页脚:展示社交图标、版权信息、备案信息、自定义信息 * ... > 文章页 * 文章信息:展示面包屑、作者、创建时间、更新时间、标签、分类、字数、阅读时长 * 评论区:提供 `Giscus`、`Twikoo`、`Waline`、`Artalk` 四种评论提供商选择,并且支持自定义评论区 * 代码块:UI 升级,支持一键折叠/展开 * 文章页风格书页化:提供 3 种风格选择:VitePress 原生、整体卡片化、片段卡片化 * 文章打赏:支持 3 种打赏风格选择 * 文章分享:提供一键复制文章链接功能 * 最近更新栏:展示最近更新文章 * ... > 功能页 * 分类页 * 标签页 * 归档页 * 清单页 * 登录页 * 风险链接提示页 除了上述功能,Teek 也提供了各种 `CSS` 文件来增强 VitePress 的样式,并提供大量的插槽支持二次开发。 如果您是其他主题的用户,也可以按需引入 Teek 的功能,增强自己的站点风格。 --- --- url: /20.资源/10.功能拓展/01.简介.md --- # 简介 本专题介绍一些基于 Teek 的扩展功能,这些功能并没有内置到 Teek 里,需要自行在自己的项目实现。 什么功能不会在 Teek 实现呢? * 需要安装额外依赖的功能,因为 Teek 主打轻量,因此只保留运行时或者核心功能需要的依赖 * 只能在项目里实现的功能,如导航栏添加图标 --- --- url: /15.主题开发/30.组件布局.md --- # 组件结构 一个项目的功能组件虽然有很多,但是入口组件只有一个,如果您不知道这些功能组件都在哪里执行,不妨从入口组件开始解读,一步一步往下延伸,最终把项目功能吃透。 Teek 在首页、文章页、空白页、全局都写了组件来实现功能,但是这些组件并不是分开引入,而是统一在 `Layout` 组件里引入,并派发到 VitePress 不同的插槽,如: ```vue ``` ## 目录结构 ```sh src │ ├─ components │ ├─ base # 基础样式组件 │ │ │ ├─ common # 公共组件 │ │ ├─ article-page # 文章页组件 │ │ ├─ avatar # 头像组件 │ │ ├─ breadcrumb # 面包屑组件 │ │ ├─ focus-trap # 聚焦组件 │ │ ├─ icon # 图标组件 │ │ ├─ image-viewer # 图片查看器组件 │ │ ├─ input-slide # 滑块组件 │ │ ├─ message # 消息提示组件 │ │ ├─ home-card # 分页卡片组件 │ │ ├─ pagination # 分页组件 │ │ ├─ popover # 弹窗组件 │ │ ├─ segmented # 分段控制器组件 │ │ ├─ title-tag # 标题标签组件 │ │ ├─ transition-collapse # 折叠动画组件 │ │ ├─ verify-code # 随机验证码组件 │ │ ├─ vp-container # VitePress 容器组件 │ │ │ ├─ theme # 主题组件 │ │ ├─ article-analyze # 文章页分析组件 │ │ ├─ article-appreciation # 文章页赞赏组件 │ │ ├─ article-banner # 文章页 Banner 组件 │ │ ├─ article-breadcrumb # 文章页面包屑组件 │ │ ├─ article-code-block # 代码块加强组件 │ │ ├─ article-heading-highlight # 文章页标题高亮组件 │ │ ├─ article-image-preview # 图片预览组件 │ │ ├─ article-info # 文章信息组件 │ │ ├─ article-page-style # 文章页样式组件 │ │ ├─ article-share # 文章页分页组件 │ │ ├─ article-title # 文章标题组件 │ │ ├─ article-update # 文章最近更新栏组件 │ │ ├─ body-bg-image # Body 背景图片组件 │ │ ├─ comment-artalk # Artalk 评论区组件 │ │ ├─ comment-giscus # Giscus 评论区组件 │ │ ├─ comment-twikoo # Twikoo 评论区组件 │ │ ├─ comment-waline # Waline 评论区组件 │ │ ├─ config-provider # Teek 入口文件 │ │ ├─ demo-code # Demo 容器组件 │ │ ├─ footer-group # 底部信息组组件 │ │ ├─ footer-info # 底部信息组件 │ │ ├─ home-banner # 首页 Banner 组件 │ │ ├─ home-card # 首页卡片栏组件 │ │ ├─ home-card-category # 首页分类卡片组件 │ │ ├─ home-card-doc-analysis # 首页文章分析卡片组件 │ │ ├─ home-card-friend-link # 首页友情链接卡片组件 │ │ ├─ home-card-my # 首页我的卡片组件 │ │ ├─ home-card-tag # 首页标签卡片组件 │ │ ├─ home-card-top-article # 首页置顶文章卡片组件 │ │ ├─ home-feature # 首页 banner 的 Feature 组件 │ │ ├─ home-fullscreen-wallpaper # 壁纸模式组件 │ │ ├─ home-main # 首页组件 │ │ ├─ home-post # 首页文章列表组件 │ │ ├─ layout # 布局组件(入口组件) │ │ ├─ notice # 公告组件 │ │ ├─ page-archives # 归档页组件 │ │ ├─ page-article-overview # 清单页组件 │ │ ├─ page-catalogue # 目录页组件 │ │ ├─ page-login # 登录页 │ │ ├─ page-risk-link # 风险链接提示页 │ │ ├─ right-bottom-button # 右下角按钮组组件 │ │ ├─ route-loading # 路由切换加载动画组件 │ │ ├─ sidebar-trigger # 侧边栏折叠/展开组件 │ │ ├─ theme-enhance # 主题增强面板组件 ``` VitePress 从 `src/index.ts`(入口文件)解析 `Layout` 函数,该函数返回 `src/layout.index.vue` 组件(入口组件),该入口组件将 Teek 的各个功能组件派发到 VitePress 不同的插槽,最终形成现在的 Teek 主题。 ## 配置项获取 在开发功能组件的时候,Teek 往往不会在组件内部固定功能,而是由用户通过配置项来开关功能。 在 VitePress 中,配置项往往有 2 种方式配置: 1. `.vitepress/config.mts` 全局配置 2. Markdown 的 `frontmatter` 局部配置 如果 2 种方式都配置,那么 Markdown 的 `frontmatter` 配置优先级更改,比如 Teek 的评论区功能,用户可以给每一个 Markdown 配置不同的评论区。 配置项获取的例子如: ```vue ``` 这样编写方式既支持 2 种方式配置,也支持给配置项添加默认值。2 种配置方式如下(`index.md ` 和 `文章页.md` 是 `frontmatter` 方式): ::: code-group ```ts [config] // .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 [index.md] --- tk: comment: provider: "giscus" options: repo: "your repo" repoId: "your repoId" category: "your category" categoryId: "your categoryId" --- ``` ```yaml [文章页.md] --- comment: provider: "giscus" options: repo: "your repo" repoId: "your repoId" category: "your category" categoryId: "your categoryId" --- ``` ::: --- --- url: /01.指南/01.简介/20.结构化目录.md --- # 结构化目录 ## 目录结构 在运行或构建 Teek 时,Teek 会按照目录结构自动生成一个结构化的 **侧边栏**、**目录树**、**面包屑**、**文章列表**、**文章分析** 等数据。 侧边栏和目录树的标题获取有如下特性: * 针对文件夹,先分别扫描该文件夹下的 `index.md`、`index.MD`、`[文件夹名].md` 文件,并尝试获取文件的 `frontmatter.title` 或一级标题,如果获取到标题,则使用,否则使用文件夹名 * 针对 Markdown 文档,其获取顺序:`frontmatter.title` > Markdown 文件一级标题 > Markdown 文件名 面包屑的标题默认按照 Markdown 文件所在的目录层级名进行获取。 Teek 建议给每个 Markdown 文件设置 `frontmatter.title`,且文件的命名与 `frontmatter.title` 保持一致。 ::: info 侧边栏数据会在文章页左侧生成菜单,目录树数据会在目录页生成目录,面包屑数据会在文章页生成面包屑。 ::: ## 特殊目录 Teek 的自动生成侧边栏,自动生成 `frontmatter`、自动生成 `h1` 标题、站点分析功能在 VitePress 启动后,从根目录扫描 Markdown 文件,但是有部分目录会忽略扫描: * `@pages`:该目录初衷是存放归档页、分类页、标签页等非文章的 Markdown 文件,它完全不会被 Teek 扫描,它是非常纯净的目录 * `.scripts`:该目录初衷是存放一些脚本、工具文件,它完全不会被 Teek 扫描,它是非常纯净的目录 * `@fragment`:该目录下的 Markdown 文件不会自动生成侧边栏,因此一些 **碎片化** 文章建议放在该目录下 * `/目录页/`:该命名的目录(正则表达式,如 `01.目录页` 也符合)初衷是提供一个专门存放目录页的 Markdown 文件,因此统计站点文章数、文章总数等功能不会扫描该目录,文章列表和归档页也不会扫描该目录 ::: details 碎片化文章说明 特点 * 简短且独立:每个碎片化文章通常只涵盖一个具体的知识点或主题,篇幅较短 * 灵活性高:可以随时添加、修改或删除,不受整体结构的严格限制 * 易于管理:由于其独立性,管理和查找特定知识点更加方便 * 补充性质:通常作为主干内容的补充,提供额外的信息或细节 示例场景 * 技术笔记:例如某个命令的用法、某个库的简单示例等 * 个人心得:如读书笔记、会议纪要等 * 临时记录:开发过程中遇到的问题及解决方案 ::: ::: info 如果自动生成侧边栏规则为 `rewrites`,则满足这些特殊目录的条件是:`rewrites` 的 Markdown 前缀以这些值开头。 ::: ## 命名约定 ### 博客风 如果你搭建的是博客风的站点,那么 Teek 建议和 vdoing 一样,使用以下命名约定: * 无论是文件还是文件夹,请为其名称添加上正确的正整数序号和 `.`,从 `00` 或 `01` 开始累计,如 `01.文件夹`、`02.文件.md`,Teek 将会按照序号的顺序来决定其在侧边栏当中的顺序 * 同一级别目录别内即使只有一个文件或文件夹也要为其加上序号 序号只是用于决定先后顺序,并不一定需要连着,如 `01、02、03...`,实际可能会在两个文章中间插入一篇新的文章,因此为了方便可以采用间隔序号 `10、20、30...`,后面如果需要在 `10` 和 `20` 中间插入一篇新文章,可以给定序号 `15`。 当然可以使用非序号的命名,这并不影响使用,添加序号只是为了排序,且更具有结构化,如果同一个目录下同时存在带序号和不带序号的文件,在生成侧边栏时,Teek 会分为两个区:带序号区和不带序号区,两个区内部按照各自的逻辑排序,在最终生成侧边栏的时候,不带序号区始终放在带序号区的后面。 ::: tip 从维护性、可读性的角度分析,带有序号的文件名在本地目录看起来更加直观;从站点渲染的角度分析,在生成侧边栏时,Teek 会根据文件名的序号进行排序。 ::: 如果不希望 URL 上带有序号,请给每一个 Markdown 指定一个永久链接 [frontmatter.permalink](http://localhost:5173/reference/frontmatter.html#permalink)。 ### 文档风 如果你搭建的是文档风,那么大部分场景下,Markdown 文件名为英文格式,此时正好作为 URL 访问,此时会遇到一个问题:在生成侧边栏时,怎么按照自己的要求进行排序呢? * 仿照博客风给文件名添加序号,但是访问时 URL 会带上序号,这样看起来比较难受,为解决这个问题,你需要指定一个永久链接 `frontmatter.permalink` * 文件名不添加序号,通过 `frontmatter.sidebarSort` 指定排序,数值越小越靠前,数值的命名规则可以参考博客风:序号之间添加间隔 如果不指定 `frontmatter.sidebarSort`,那么 Teek 给每一个文件默认设置为 `9999`,因此如果给某一个文件的 `frontmatter.sidebarSort` 设置大于 9999,则排在侧边栏的最后面。 > 我可以自定义默认 9999 为其他序号吗?或者希望文件名本身有序号时,则替换 9999? 这是可以的,配置如下: ```ts {6-8} import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ vitePlugins: { sidebarOption: { sort: true, // 开启 frontmatter.sidebarSort 功能,默认已经开启,无需设置 defaultSortNum: 9999, // 没有指定 frontmatter.sidebarSort 时的默认值,用于侧边栏排序 sortNumFromFileName: false, // 是否用文件名的前缀序号作为其侧边栏 Item 的排序序号。如果为 true,当文件名存在序号前缀,则使用序号前缀,否则使用 defaultSortNum // ... 更多配置 }, }, }); ``` 更多的其他配置请看 [SideBar 配置项](https://github.com/Kele-Bingtang/vitepress-theme-teek/blob/master/plugins/vitepress-plugin-sidebar-resolve/src/types.ts)。 ## 目录层级 Teek 生成侧边栏或目录树的数据时,虽然支持无限层嵌套,但是建议不要超过 5 层。 ## 目录结构例子 这里以博客风的命名约定为例: ```sh . │ (不参与数据生成) ├─ .vitepress ├─ .scripts ├─ @pages ├─ @fragment ├─ index.md ├─ package.json │ │ (以下部分参与数据生成) ├─ 01.指南 │ │ index.md │ ├─ 01.指南 - 使用 │ │ ├── 04.使用 - 登录认证.md │ │ ├── 07.使用 - 权限认证.md │ │ ├── 10.使用 - 登出下线.md │ │ ├── 13.使用 - 注解鉴权.md │ │ ├── 16.使用 - 路由拦截鉴权.md │ │ ├── 19.使用 - Session 会话.md │ │ ├── 22.使用 - 框架配置.md │ │ ├── 25.使用 - 自定义 Token.md │ │ ├── 28.使用 - 临时 Token 认证.md │ │ ├── 31.使用 - 记住我模式.md │ │ ├── 34.使用 - 二级认证.md │ │ ├── 37.使用 - 身份切换.md │ │ ├── 40.使用 - 账号封禁.md │ │ ├── 43.使用 - 会话查询.md │ │ ├── 46.使用 - Http Basic 认证.md │ │ ├── 49.使用 - 全局侦听器.md │ │ ├── 52.使用 - 全局过滤器.md │ │ ├── 55.使用 - 多账号认证.md │ │ ├── 58.使用 - 自定义注解.md │ │ └─ 99.三级目录测试 │ │ │ ├── 01.测试1.md │ │ │ ├── 03.测试2.md │ │ │ ├── index.md │ │ │ │ └─ 99.四级目录测试 │ │ │ │ ├── 01.测试1.md │ │ │ │ ├── 03.测试2.md │ │ │ │ ├── index.md │ ├─ 05.指南 - 环境集成 │ │ ├── 04.环境集成 - Spring Boot.md │ │ ├── 07.环境集成 - Spring WebFlux.md │ │ ├── 99.环境集成 - 上下文组件开发指南.md │ └─ 10.指南 - 插件 │ │ ├── 04.插件 - 持久层集成 Redis.md │ │ ├── 07.插件 - 持久层拓展.md │ │ ├── 10.插件 - AOP 注解鉴权.md │ │ ├── 13.插件 - Token 集成 JWT.md │ │ ├── 99.插件 - 插件开发指南.md ├─ 05.设计 │ │ 00.目录.md │ ├─ 01.设计 - 思路 │ │ │ 01.设计 - 思路设计.md │ │ │ 04.设计 - 模块设计.md │ │ │ 07.设计 - 术语说明.md │ │ │ 10.设计 - 全局配置.md │ │ │ 13.设计 - 策略模式.md │ │ │ 16.设计 - 异常模型.md │ │ │ 18.设计 - 管理者模型.md │ ├─ 03.设计 - Helpers │ │ ├── 01.设计 - Helpers 说明.md │ │ ├── 07.设计 - 账号登录.md │ │ ├── 10.设计 - 账号登出.md │ │ ├── 13.设计 - 账号封禁.md │ │ ├── 16.设计 - 二级认证.md │ │ ├── 19.设计 - 身份切换.md │ │ ├── 22.设计 - 账号认证.md │ │ ├── 25.设计 - 临时 Token.md │ │ ├── 28.设计 - 同源 Token.md │ │ ├── 31.设计 - Http Basic 认证.md ``` --- --- url: /10.配置/01.主题配置/35.评论配置.md --- # 评论配置 ## comment 评论配置,目前内置 `Giscus`、`Twikoo`、`Waline`、`Artalk` 四种评论插件。 ::: tip 支持每个文章页配置不同的在评论区提供者 `provider`。 ::: ::: code-group ```ts [config.mts] // .vitepress/config.mts import { defineTeekConfig } from "vitepress-theme-teek/config"; const teekConfig = defineTeekConfig({ comment: { provider: "giscus", // 评论区提供者 // 评论区配置项,根据 provider 不同而不同,具体看对应官网的使用介绍 options: { // twikoo 配置,官网:https://twikoo.js.org/ // envId: "your envId", // waline 配置,官网:https://waline.js.org/ // serverURL: "your serverURL", // jsLink: "https://unpkg.com/@waline/client@v3/dist/waline.js", // cssLink: "https://unpkg.com/@waline/client@v3/dist/waline.css", // giscus 配置,官网:https://giscus.app/zh-CN repo: "your repo", repoId: "your repoId", category: "your category", categoryId: "your categoryId", // artalk 配置,官网:https://artalk.js.org/ // server: "your server", // site: "site", }, }, }); ``` ```yaml [文章页 xxx.md] --- tk: comment: provider: giscus options: repo: your repo repoId: your repoId category: your category categoryId: your categoryId --- ``` ```ts [更多配置项] interface TeekConfig { /** * 评论配置 */ comment?: | CommentConfig<"twikoo"> | CommentConfig<"waline"> | CommentConfig<"giscus"> | CommentConfig<"artalk"> | CommentConfig<"render">; } type CommentConfig = { /** * 评论区提供者 * twikoo 官网:https://twikoo.js.org/ * waline 官网:https://waline.js.org/ * giscus 官网:https://giscus.app/zh-CN * artalk 官网:https://artalk.js.org/ * render 需要自定义评论区组件,并通过 comment 插槽传入 */ provider: T; /** * 评论区配置项,根据 provider 不同而不同,具体看对应官网的使用介绍 */ options?: CommentProvider[T]; }; export type CommentProvider = { /** * twikoo 评论区配置项 */ twikoo: { /** * 官网其他配置项 */ [key: string]: any; envId: string; /** * twikoo.js 在线链接 * * @default 'https://cdn.jsdelivr.net/npm/twikoo@{version}/dist/twikoo.nocss.js' */ jsLink?: string; /** * twikoo.css 在线链接 * * @default 'https://cdn.jsdelivr.net/npm/twikoo@{version}/dist/twikoo.css' */ cssLink?: string; /** * twikoo 版本号,不定期更新为最新版 * * @default '1.6.42' */ version?: string; /** * twikoo 的 css、js 的 integrity */ jsIntegrity?: string; /** * 页面渲染后多少毫秒开始渲染 twikoo,如果设置太短,可能获取的 DOM 还没加载完成 * * @default 700 (0.7秒) */ timeout?: number; /** * katex 配置项,如果设置,则加载 katex */ katex?: { /** * katex 的 css、core、render 的在线链接 */ cssLink: string; coreJsLink: string; renderJsLink: string; /** * katex 的 css、core、render 的 integrity */ cssIntegrity?: string; coreJsIntegrity?: string; renderJsIntegrity?: string; }; }; /** * waline 评论区配置项 */ waline: { /** * 官网其他配置项 */ [key: string]: any; /** * waline 后台服务器地址 */ serverURL: string; /** * waline.js 在线链接 */ jsLink?: string; /** * waline.css 在线链接 */ cssLink?: string; /** * waline.css 的 integrity */ cssIntegrity?: string; /** * 暗黑模式,具体使用请看 waline 官网 * * @default "html[class='dark']" */ dark?: string; }; /** * giscus 评论区配置项 */ giscus: { [key: string]: any; repo: `${string}/${string}`; repoId: string; category: string; categoryId: string; mapping?: "url" | "title" | "og:title" | "specific" | "number" | "pathname"; strict?: "0" | "1"; reactionsEnabled?: "0" | "1"; emitMetadata?: "0" | "1"; inputPosition?: "top" | "bottom"; lang?: string; theme?: string; loading?: "lazy" | "eager"; /** * 是否使用在线链接 * * @default true */ useOnline?: boolean; /** * giscus.js 在线链接,useOnline 为 true 时生效 * * @default 'https://giscus.app/client.js' */ link?: string; /** * giscus.js 的 integrity */ integrity?: string; }; /** * artalk 评论区配置项 */ artalk: { [key: string]: any; /** * artalk 后台服务器地址 */ server: string; /** * artalk 站点名称 */ site: string; }; /** * 自定义评论组件 */ render: Record; }; ``` ::: 如果您使用 Twikoo,你只需要传入 `version` 版本号即可,Teek 会根据版本号去分别请求 Twikoo 的 JS、CSS 文件,其请求地址分别为: * JS:`https://cdn.jsdelivr.net/npm/twikoo@{version}/dist/twikoo.nocss.js` * CSS:`https://cdn.jsdelivr.net/npm/twikoo@{version}/dist/twikoo.css` ::: tip 如果您无法访问 `cdn.jsdelivr.net`,则可以通过 `jsLink` 和 `cssLink` 配置项来手动传入链接地址,但是 Teek 建议不要传入 `twikoo.all.min.js` 或 `twikoo.min.js` 的在线链接,而是传入 `twikoo.nocss.js` 和 `twikoo.css` 在线链接。 原因:`twikoo.all.min.js` 或 `twikoo.min.js` 内部会自动引入 Twikoo 的 CSS 文件,该 CSS 文件会全局影响 Teek 的样式,因此请手动传入 `twikoo.nocss.js` 和 `twikoo.css` 在线链接,Teek 会让其样式局部生效。 ::: ## 评论区实例注入 在 `comment` 配置项里,评论区的实例都是通过传入在线 JS、CSS 链接来实现,如果网速不好或者在线链接无法访问,那么评论区会无法正常加载。 Teek 支持手动传入评论区的实例,因此您可以安装评论区的依赖,然后按照官方的 API 初始化实例后传给 Teek。 首先安装评论插件依赖(按需安装): ```sh # 安装 Waline 依赖 pnpm add -D @waline/client # 安装 Giscus 依赖 pnpm add -D @giscus/vue # 安装 Artalk 依赖 pnpm add -D artalk # 安装 Twikoo 依赖 pnpm add twikoo ``` 然后在 `.vitepress/theme/index.ts` 里面注入评论区的实例。 ```ts {2,6-7,9,11-12,14,25-37} // .vitepress/theme/index.ts import Teek, { artalkContext, giscusContext, walineContext, twikooContext } from "vitepress-theme-teek"; import "vitepress-theme-teek/index.css"; import { useData, useRoute } from "vitepress"; import { init } from "@waline/client"; import "@waline/client/style"; import Giscus from "@giscus/vue"; import Artalk from "artalk"; import "artalk/Artalk.css"; import twikoo from "twikoo"; export default { extends: Teek, Layout: defineComponent({ name: "LayoutProvider", setup() { const { isDark, page } = useData(); const route = useRoute(); // 注入评论区实例 provide(walineContext, (el, options) => init({ serverURL: options.serverURL!, dark: options.dark, el })); provide(giscusContext, () => Giscus); provide(artalkContext, (el, options) => Artalk.init({ el, darkMode: isDark.value, pageKey: route.path, pageTitle: page.value.title, server: options.server, site: options.site, }) ); provide(twikooContext, (el, options) => twikoo.init({ ...options, el })); return () => h(Teek.Layout, null, {}); }, }), }; ``` ::: tip 这些依赖都是评论插件官方文档提供的,如果无法安装/注入成功,请前往对应官方文档阅读如何安装依赖、初始化实例。 ::: 最后可以把 `config` 里的在线链接配置项删除,当然您也可以保留,当两者同时存在,以评论区实例注入为主。 ## 自定义评论区 如果这四个评论区提供者都不符合需求,可以自己实现评论区,然后传入进来。 先把 `provider` 必须指定为 `render`。 ```ts // .vitepress/config.mts const teekConfig = defineTeekConfig({ comment: { provider: "render", // 自定义评论区必须指定 render }, }); ``` 最后通过 `teek-comment` 插槽传入自定义评论区组件。 ```ts // .vitepress/theme/index.ts import Teek from "vitepress-theme-teek"; import "vitepress-theme-teek/index.css"; import MyCommentComponent from "./components/MyCommentComponent.vue"; import { h } from "vue"; export default { extends: Teek, Layout() { return h(Teek.Layout, null, { "teek-comment": () => h(MyCommentComponent), }); }, }; ``` --- --- url: /01.指南/40.开发/05.贡献指南.md --- # 贡献指南 感谢您使用 Teek。 以下是关于向 Teek 提交反馈或代码的指南。在向 Teek 提交 Issue 或者 PR 之前,请先花几分钟时间阅读以下内容。 ## Issue 规范 * 遇到问题时,请先确认这个问题是否已经在 Issue 中有记录或者已被修复 * 提 Issue 时,请用简短的语言描述遇到的问题,并添加出现问题时的环境和复现步骤,必要时需提供可复现问题最小代码仓库 环境包含 * `浏览器` 版本 * `操作系统` 版本 * `node` 版本 * `vitepress` 版本 * `Teek` 版本 ## 参与开发 参考 [开发指南](/guide/dev)。 ### 代码规范 在编写代码时,请注意: * 确保代码可以通过仓库的 `ESLint` 校验 * 确保代码格式是规范的,使用 `prettier` 进行代码格式化 ## 提交 Pull Request ### 参考指南 如果你是第一次在 GitHub 上提 Pull Request ,可以阅读下面这两篇文章来学习: * [第一次参与开源](https://github.com/firstcontributions/first-contributions/blob/main/translations/README.zh-cn.md) * [如何优雅地在 GitHub 上贡献代码](https://segmentfault.com/a/1190000000736629) ### Pull Request 规范 在提交 Pull Request 时,请注意: * 保持你的 PR 足够小,一个 PR 只解决单个问题或添加单个功能 * 在 PR 中请添加合适的描述,并关联相关的 Issue ### Pull Request 流程 1. fork 主仓库,如果已经 fork 过,请同步主仓库的最新代码 2. 基于 fork 后仓库的 dev 分支新建一个分支,比如 feature/docs 3. 在新分支上进行开发,开发完成后,提 Pull Request 到主仓库的 dev 分支 4. Pull Request 会在 Review 通过后被合并到主仓库 5. 等待 Teek 发布新版本 ### Pull Request 标题格式 Pull Request 的标题应该遵循以下格式: ```sh type(scoped):commit message ``` 示例: * docs: add contribution.md * build: optimize build speed * fix(component(icon)): incorrect style * feat(composables(useVpRouter)): add new function 可选的类型: * feat * fix * docs * style * refactor * perf * test * build * ci * chore * revert * wip * types ## 同步最新代码 提 Pull Request 前,请依照下面的流程同步主仓库的最新代码: ```sh # 添加主仓库到 remote git remote add upstream https://github.com/Kele-Bingtang/vitepress-theme-teek.git # 拉取主仓库最新代码 git fetch upstream # 切换至 dev 分支 git checkout dev # 合并主仓库代码 git merge upstream/dev ``` --- --- url: /01.指南/20.相关/05.路由钩子.md --- # 路由钩子 VitePress 提供的 `useRouter` 有 4 个路由钩子,分别为: * `onBeforeRouteChange`:路由变化前触发,如果在该钩子函数中返回 `false`,则不会进行路由跳转 * `onBeforePageLoad`:页面加载前执行,在 `onBeforeRouteChange` 之后触发,如果在该钩子函数中返回 `false`,则不会进行路由跳转 * `onAfterPageLoad`:页面加载后执行 * `onAfterRouteChange`:路由变化后触发,在 `onAfterPageLoad` 之后触发 Teek 内置的 4 个评论区组件使用了 `onAfterRouteChange` 钩子函数,且 `vitepress-plugin-permalink` 插件分别使用了 `onBeforeRouteChange` 和 `onAfterRouteChange` 两个路由钩子。 如果您也需要使用这些路由钩子,请不要直接这样使用: ```ts router.onAfterRouteChange = (href: string) => { // 你的逻辑 }; ``` `onAfterRouteChange` 是一个函数,您这样使用将会 **覆盖** Teek 在该钩子函数的逻辑,因此您需要这样使用: ```vue ``` `onBeforeRouteChange` 支持返回 false 来阻止路由跳转,因此请这样使用: ```vue ``` ## useVpRouter 针对上面较为复杂的配置,Teek 已经封装了 Composables 函数 `useVpRouter`,该函数对 VitePress 的 `router` 钩子进行封装,因此您可以这样使用: ```vue ``` 如果您想一次性绑定多个 `router` 钩子,可以这样使用: ```vue ``` --- --- url: /30.生态/05.运行时 API.md --- # 运行时 API Teek 提供了几个内置的 API 来让你访问应用程序数据,这些 API 只能在 `setup()` 或 `