Skip to content

导航栏图标

导航栏添加图标

HTML 方式

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

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/",
      },
    ],
  },
});

组件方式

警告

组件方式不能作用在父级导航上。

上面的方法需要传入一个 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 组件