00:00:00
导航栏图标
导航栏添加图标
HTML 方式
在 .vitepress/config.mts 的 themeConfig.nav 配置项中添加图标 HTML:
ts
import { defineConfig } from "vitepress";
export default defineConfig({
themeConfig: {
nav: [
{
text: "<i class='iconfont icon-guide'></i> 指南",
link: "http://vp.teek.top/",
},
],
},
});1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
ts
import { defineConfig } from "vitepress";
export default defineConfig({
themeConfig: {
nav: [
{
text: `
<div style="display: flex; align-items: center; gap: 4px;">
<img src="your img link" alt="" style="width: 16px; height: 16px;">
<span>指南</span>
</div>
`,
link: "http://vp.teek.top/",
},
],
},
});1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Teek 内置的 iconfont 仅仅是 社交图标,更多 iconfont 图标可以去 阿里巴巴矢量图标库 下载。
举个例子:
假设您已经下载了一组 iconfont 图标,其目录结构应该如下:
sh
.
├─ iconfont.css
├─ iconfont.js
├─ iconfont.json
├─ iconfont.ttf
├─ iconfont.woff
├─ iconfont.woff21
2
3
4
5
6
7
2
3
4
5
6
7
将该目录放到 .vitepress/theme/assert/iconfont 下(实际按照自己的路径存放),然后在 .vitepress/theme/index.ts 文件里引入:
ts
import "./assets/iconfont/system/iconfont.js";
import "./assets/iconfont/system/iconfont.css";1
2
2
接下来在通过 <i class="iconfont icon-{xxx}"></i> 在导航栏、侧边栏等位置使用图标。
添加样式
- 使用内联样式
<i class="iconfont icon-{xxx}" style="color: var(--tk-el-color-danger)"></i> - 自定义一个
class,然后编写样式
组件方式
警告
组件方式不能作用在父级导航上。
上面的方法需要传入一个 HTML 标签来实现,如果有很多导航配置,那么写起来很麻烦,且可读性较差,
在 .vitepress/theme/components 自定义一个组件 NavIcon.vue 来进行封装:
vue
<!-- .vitepress/theme/components/NavIcon.vue -->
<script setup lang="ts">
import type { DefaultTheme } from "vitepress/theme";
import type { TkIconProps } from "vitepress-theme-teek";
import { useData } from "vitepress";
import { TkIcon, isClient } from "vitepress-theme-teek";
import { VPLink } from "vitepress/theme";
defineProps<DefaultTheme.NavItemWithLink & { iconProps?: TkIconProps; subMenu?: boolean }>();
const { page } = useData();
const HASH_RE = /#.*$/;
const HASH_OR_QUERY_RE = /[?#].*$/;
const INDEX_OR_EXT_RE = /(?:(^|\/)index)?\.(?:md|html)$/;
const isActive = (currentPath: string, matchPath?: string, asRegex: boolean = false) => {
if (matchPath === undefined) return false;
currentPath = normalize(`/${currentPath}`);
if (asRegex) return new RegExp(matchPath).test(currentPath);
if (normalize(matchPath) !== currentPath) return false;
const hashMatch = matchPath.match(HASH_RE);
if (hashMatch) return (isClient ? location.hash : "") === hashMatch[0];
return true;
};
const normalize = (path: string) => {
return decodeURI(path).replace(HASH_OR_QUERY_RE, "").replace(INDEX_OR_EXT_RE, "$1");
};
</script>
<template>
<div :class="{ Icon: iconProps?.icon }">
<VPLink
:class="{
VPNavBarMenuLink: !subMenu,
SubMenu: subMenu,
active: isActive(page.relativePath, activeMatch || link, !!activeMatch),
}"
:href="link"
:target="target"
:rel="rel"
:no-icon="noIcon"
tabindex="0"
>
<TkIcon v-if="iconProps?.icon" v-bind="iconProps" />
<span v-html="text"></span>
</VPLink>
</div>
</template>
<style scoped>
.VPNavBarMenuLink {
display: flex;
align-items: center;
padding: 0 12px;
line-height: var(--vp-nav-height);
font-size: 14px;
font-weight: 500;
color: var(--vp-c-text-1);
transition: color 0.25s;
}
.VPNavBarMenuLink.active {
color: var(--vp-c-brand-1);
}
.VPNavBarMenuLink:hover {
color: var(--vp-c-brand-1);
}
.tk-icon {
margin-right: 7px;
}
.SubMenu {
display: flex;
align-items: center;
border-radius: 6px;
padding: 0 12px;
line-height: 32px;
font-size: 14px;
font-weight: 500;
color: var(--vp-c-text-1);
white-space: nowrap;
transition:
background-color 0.25s,
color 0.25s;
}
.SubMenu:hover {
color: var(--vp-c-brand-1);
background-color: var(--vp-c-default-soft);
}
</style>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
然后在 .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);
},
};1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
最后在 themeConfig.nav 使用:
ts
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",
},
},
},
],
},
],
},
});1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
NavIcon组件的props里的配置项和VitePress的nav配置项一致iconProps是TkIcon组件的props,更多具体 API 用法请参考 TkIcon 组件