Skip to content
On this page

快速搭建网站

vitepress

vitepress,VitePress 是一个静态网站生成器(SSG),专为构建快速、以内容为中心的网站而设计。简而言之,VitePress 获取您用Markdown编写的源内容,对其应用主题,并生成可以轻松部署到任何地方的静态 HTML 页面。

适用于开发文档、博客等

vitepress 模板

在线示例:查看

仓库地址:new-vitepress-demo - SuYxh - github

实用 markdown 扩展

参考: markdown-extensions - vitepress

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.

bash
::: 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.
:::
::: 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.
:::

custom title

STOP

Danger zone, do not proceed

Click me to view the code
js
console.log('Hello, VitePress!')
console.log('Hello, VitePress!')
bash
::: danger STOP
Danger zone, do not proceed
:::

::: details Click me to view the code
# ```js
console.log('Hello, VitePress!')
# ```
:::
::: danger STOP
Danger zone, do not proceed
:::

::: details Click me to view the code
# ```js
console.log('Hello, VitePress!')
# ```
:::

图片放大/图片预览

使用 vitepress-plugin-image-viewer 插件

点击下图,查看效果

img-zoom-in

安装使用

安装依赖

bash
npm i vitepress-plugin-image-viewer --save
npm i sass --save
npm i vitepress-plugin-image-viewer --save
npm i sass --save

引入下面的代码后,markdown 文档中的图片会自动加上预览功能。

js
// .vitepress\theme\index.ts
import Theme from "vitepress/theme";
import "./style/var.css";

// 图片放大/预览
import "viewerjs/dist/viewer.min.css";
import imageViewer from "vitepress-plugin-image-viewer";
import vImageViewer from "vitepress-plugin-image-viewer/lib/vImageViewer.vue";
import { useRoute } from "vitepress";

export default {
  ...Theme,
  enhanceApp({ app }) {
    // 注册全局组件,如果你不想使用也可以不添加
    app.component("vImageViewer", vImageViewer);
  },
  setup() {
    // 获取路由
    const route = useRoute();
    // 使用
    imageViewer(route);
  },
};
// .vitepress\theme\index.ts
import Theme from "vitepress/theme";
import "./style/var.css";

// 图片放大/预览
import "viewerjs/dist/viewer.min.css";
import imageViewer from "vitepress-plugin-image-viewer";
import vImageViewer from "vitepress-plugin-image-viewer/lib/vImageViewer.vue";
import { useRoute } from "vitepress";

export default {
  ...Theme,
  enhanceApp({ app }) {
    // 注册全局组件,如果你不想使用也可以不添加
    app.component("vImageViewer", vImageViewer);
  },
  setup() {
    // 获取路由
    const route = useRoute();
    // 使用
    imageViewer(route);
  },
};

用户体验

为了更好的用户体验,可以增加鼠标移动到图片时,变成放大镜的效果,css 如下

css
/* .vitepress\theme\style\var.css */
.main img {
  cursor: zoom-in; /* 移动到图片上,可放大 */
}
/* .vitepress\theme\style\var.css */
.main img {
  cursor: zoom-in; /* 移动到图片上,可放大 */
}

点击按钮打开图片

另外该插件还内置了点击按钮,查看图片的功能组件 vImageViewer

代码如下:

html
<vImageViewer src="/images/互联网技术.png" alt="点击按钮查看图片" :inline="false"/>
<vImageViewer src="/images/互联网技术.png" alt="点击按钮查看图片" :inline="false"/>

其中,inline 属性设置为 true,那么它会变成一个行内元素,他不是必需的,默认为 false

评论系统

使用 valine 提供的评论功能

注册 valine

1、根据官网,先去注册 LeanCloud

2、按照说明文档,一步步操作,创建一个应用,然后获取到 APP ID 和 APP Key

Valine.min.js - cdn 文件放到 public/js/ 目录下,因为用 npm 包在 build 时会出现 ReferenceError: window is not defined 错误,需要通过 cdn/js 引入

每篇文章底部添加评论

使用 doc-after 插槽在每篇文章中增加评论组件

html
<!-- .vitepress\theme\MyLayout.vue -->
<script setup>
import DefaultTheme from 'vitepress/theme'
import ValineComment from './ValineComment.vue';
const { Layout } = DefaultTheme
</script>

<template>
  <Layout>
    <template #doc-after>
      <ValineComment />
    </template>
  </Layout>
</template>
<!-- .vitepress\theme\MyLayout.vue -->
<script setup>
import DefaultTheme from 'vitepress/theme'
import ValineComment from './ValineComment.vue';
const { Layout } = DefaultTheme
</script>

<template>
  <Layout>
    <template #doc-after>
      <ValineComment />
    </template>
  </Layout>
</template>

修改主题布局入口文件

js
// .vitepress\theme\index.ts
import Theme from "vitepress/theme";
import MyLayout from './MyLayout.vue'
import "./style/var.css";

export default {
  ...Theme,
  // override the Layout with a wrapper component that injects the slots
  Layout: MyLayout,
};
// .vitepress\theme\index.ts
import Theme from "vitepress/theme";
import MyLayout from './MyLayout.vue'
import "./style/var.css";

export default {
  ...Theme,
  // override the Layout with a wrapper component that injects the slots
  Layout: MyLayout,
};

评论组件代码,包含评论、阅读量显示

html
<!-- .vitepress\theme\ValineComment.vue -->
<template>
  <div class="comment-wrap">
    <!-- 阅读量 -->
    <div class="page-edit-read">
      <span class="leancloud-visitors" data-flag-title="dev-zuo">
        <span class="post-meta-item-text">阅读量: </span>
        <i class="leancloud-visitors-count"></i>
      </span>
    </div>
    <div id="vcomments"></div>
  </div>
</template>

<script setup>
import { onMounted, watch } from "vue";
import { useRoute } from "vitepress";
// import Valine from "valine";

const route = useRoute();

onMounted(() => {
  remoteImport("/js/Valine.min.js").then(() => initValine());
  // remoteImport('//unpkg.com/valine/dist/Valine.min.js').then(() => initValine());
});

watch(
  () => route.path,
  () => {
    console.log("监听路由变化");
    initValine();
  }
);

function initValine() {
  // 为防止本地调试访问量干扰线上数据,本地使用前缀,线上使用相对路径
  let isLocalDebug = ['http://localhost', 'http://127.0.0.1'].some(item => location.origin.startsWith(item))
  let path = isLocalDebug ? `${location.origin}${location.pathname}` : location.pathname;

  document.getElementsByClassName("leancloud-visitors")[0].id = path;
  new Valine({
    el: "#vcomments",
    appId: "xxx", // your appId
    appKey: "xx", // your appKey
    notify: false,
    verify: false,
    path: path, // window.location.pathname (默认值,推荐)
    visitor: true,
    avatar: "identicon",
    placeholder:
      "请在这里留下你的留言,如果上面填写了邮箱还能收到邮件哟,地址是点击头像跳转的地址",
    // other config
  });
}
// path
// I. 请保证每个文章页路径的唯一性,否则可能会出现不同文章页下加载相同评论列表的情况。
// II. 如果值为window.location.href,可能会出现随便加不同参数进入该页面,而被判断成新页面的情况。

function remoteImport(url) {
  return new Promise((resolve) => {
    var head = document.getElementsByTagName("head")[0];
    var script = document.createElement("script");
    script.setAttribute("type", "text/javascript");
    script.setAttribute("src", url);
    head.appendChild(script);

    script.onload = function () {
      resolve();
    };
  });
}
</script>

<style lang="scss">
.comment-wrap {
  margin-top: 20px;
  .page-edit-read {
    margin: 12px;
    text-align: right;
  }
}
</style>
<!-- .vitepress\theme\ValineComment.vue -->
<template>
  <div class="comment-wrap">
    <!-- 阅读量 -->
    <div class="page-edit-read">
      <span class="leancloud-visitors" data-flag-title="dev-zuo">
        <span class="post-meta-item-text">阅读量: </span>
        <i class="leancloud-visitors-count"></i>
      </span>
    </div>
    <div id="vcomments"></div>
  </div>
</template>

<script setup>
import { onMounted, watch } from "vue";
import { useRoute } from "vitepress";
// import Valine from "valine";

const route = useRoute();

onMounted(() => {
  remoteImport("/js/Valine.min.js").then(() => initValine());
  // remoteImport('//unpkg.com/valine/dist/Valine.min.js').then(() => initValine());
});

watch(
  () => route.path,
  () => {
    console.log("监听路由变化");
    initValine();
  }
);

function initValine() {
  // 为防止本地调试访问量干扰线上数据,本地使用前缀,线上使用相对路径
  let isLocalDebug = ['http://localhost', 'http://127.0.0.1'].some(item => location.origin.startsWith(item))
  let path = isLocalDebug ? `${location.origin}${location.pathname}` : location.pathname;

  document.getElementsByClassName("leancloud-visitors")[0].id = path;
  new Valine({
    el: "#vcomments",
    appId: "xxx", // your appId
    appKey: "xx", // your appKey
    notify: false,
    verify: false,
    path: path, // window.location.pathname (默认值,推荐)
    visitor: true,
    avatar: "identicon",
    placeholder:
      "请在这里留下你的留言,如果上面填写了邮箱还能收到邮件哟,地址是点击头像跳转的地址",
    // other config
  });
}
// path
// I. 请保证每个文章页路径的唯一性,否则可能会出现不同文章页下加载相同评论列表的情况。
// II. 如果值为window.location.href,可能会出现随便加不同参数进入该页面,而被判断成新页面的情况。

function remoteImport(url) {
  return new Promise((resolve) => {
    var head = document.getElementsByTagName("head")[0];
    var script = document.createElement("script");
    script.setAttribute("type", "text/javascript");
    script.setAttribute("src", url);
    head.appendChild(script);

    script.onload = function () {
      resolve();
    };
  });
}
</script>

<style lang="scss">
.comment-wrap {
  margin-top: 20px;
  .page-edit-read {
    margin: 12px;
    text-align: right;
  }
}
</style>

全文搜索

vitepress 如何开启 algolia 全文搜索 - YvanZhu

  • 1、申请 docsearch.algolia.com/apply/
  • 2、收到邮件后回复 Thanks!
  • 3、再次收到邮件(包含 appId、appKey)
  • 4、配置 .vitepress/config.ts
js
export default defineConfig({
  // ...
  themeConfig: {
    // ...
    algolia: {
      appId: "xx",
      apiKey: "xxxxx",
      indexName: "xxx"
    },
  }
})
export default defineConfig({
  // ...
  themeConfig: {
    // ...
    algolia: {
      appId: "xx",
      apiKey: "xxxxx",
      indexName: "xxx"
    },
  }
})

内容更新后怎么触发 algolia 重新爬取内容

在首次申请时,algolia 会第一次爬取内容。但由于我是私有仓库

内容更新后,algolia 无感知,怎么手动触发内容更新呢?

登录 https://www.algolia.com/ ,我用的是 github 登录方式,邮箱与我之前申请时使用的一致,会自动关联 index,直接进入对应管理页面

点击左下角 Data Sources => Crawler /ˈkrɔːlə(r)/ 进入管理页面 https://crawler.algolia.com/admin/crawlers 点击 Restart crawling 重新抓取,即可更新内容

广告/全局插槽

参考链接

站在前人的肩膀上