Skip to content

导航栏图标

导航栏添加图标

HTML 方式

.vitepress/config.mtsthemeConfig.nav 配置项中添加图标 HTML:

ts
import { defineConfig } from "vitepress";

export default defineConfig({
  themeConfig: {
    nav: [
      {
        text: "<i class='iconfont icon-guide'></i> 指南",
        link: "http://vp.teek.top/",
      },
    ],
  },
});
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/",
      },
    ],
  },
});

Teek 内置的 iconfont 仅仅是 社交图标,更多 iconfont 图标可以去 阿里巴巴矢量图标库 下载。

举个例子:

假设您已经下载了一组 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";

接下来在通过 <i class="iconfont icon-{xxx}"></i> 在导航栏、侧边栏等位置使用图标。

添加样式

  1. 使用内联样式 <i class="iconfont icon-{xxx}" style="color: var(--tk-el-color-danger)"></i>
  2. 自定义一个 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>

然后在 .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
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 里的配置项和 VitePressnav 配置项一致
  • iconPropsTkIcon 组件的 props,更多具体 API 用法请参考 TkIcon 组件