vitepress趣玩系列——首页内容优化

4,160 阅读3分钟

我正在参加「掘金·启航计划」

尝试开一个vitepress趣玩系列,讲一下我看到的比较有意思的vitepress玩法

上一篇文章vitepress趣玩系列——首页样式优化,我们把基本的首页内容已经完成了,还没工程的推荐先看第一篇文章,接下来做一些更有意思的处理,让首页的内容更丰富

灵感

偶然一天在看vite文档,看到它的文档也是用的vitepress设计,但会比其他的vitepress首页内容会更丰富

这是普通的

image.png

这是vite的

image.png

可以看到,vite的文档首页除了普通文档的首页内容,还实现了注脚和可交互的组件,下面我们就来跟着实现这些功能

注脚

注脚功能比较好实现,vitepress文档也有教程,就是在themeConfig中添加footer属性

// .vitepress/config.ts

import { defineConfig } from 'vitepress'

export default defineConfig({
  title: 'VitePress-Fun',
  themeConfig: {
    logo: '/cat.png',
    siteTitle: 'VitePress-Fun',

    socialLinks: [
      { icon: 'github', link: 'https://github.com/gumingWu/vitepress-fun' }
    ],

    footer: {
      message: '其实我也不知道写啥注脚',
      copyright: '那我就随便写个吧',
    }
  }
})

image.png

可以看到底部已经有注脚了

首页组件

如果我们觉得首页内容比较单调,想自己设计点可交互的内容,我们可以通过以下方案

方案一,直接写在首页md

我们在首页index.md中添加内容

---
layout: home

hero:
  name: VitePress-Fun
  text: VitePress趣玩系列
  tagline: Lorem ipsum...
  image:
    src: /cat.png
    alt: VitePress
  actions:
    - theme: brand
      text: Get Started
      link: /guide/what-is-vitepress
    - theme: alt
      text: View on GitHub
      link: https://github.com/vuejs/vitepress

features:
  - icon: ⚡️
    title: Vite, The DX that can't be beat
    details: Lorem ipsum...
  - icon: 🖖
    title: Power of Vue meets Markdown
    details: Lorem ipsum...
  - icon: 🛠️
    title: Simple and minimal, always
    details: Lorem ipsum...
---

随便写点内容

image.png

添加的内容是能直接渲染到首页的Features下,Footer上的空白部分的,由于vitepress使用的是markdown-it解析的md,所以也能直接写html标签

---
layout: home

hero:
  name: VitePress-Fun
  text: VitePress趣玩系列
  tagline: Lorem ipsum...
  image:
    src: /cat.png
    alt: VitePress
  actions:
    - theme: brand
      text: Get Started
      link: /guide/what-is-vitepress
    - theme: alt
      text: View on GitHub
      link: https://github.com/vuejs/vitepress

features:
  - icon: ⚡️
    title: Vite, The DX that can't be beat
    details: Lorem ipsum...
  - icon: 🖖
    title: Power of Vue meets Markdown
    details: Lorem ipsum...
  - icon: 🛠️
    title: Simple and minimal, always
    details: Lorem ipsum...
---

<div style="color: red; font-size: 24px;">这是个有style的随便写点</div>

image.png

我们尝试着加点class属性,让内容更丰富

image.png

可以看到,vitepress不允许用户在md中添加<script><style>标签,所以我们无法做到把style属性分离出来,和添加交互脚本,所以只有简单的特殊显示,可以直接在md文件中,通过添加html标签实现,复杂的交互和样式分离无法做到

方案二,使用vue组件

我们可以自己写一个SFC,注册到工程中,然后在md中使用

  • theme目录中创建components目录,然后创建FreeStyle.vue

    <script setup lang="ts">
    import { ref } from 'vue'
    
    const num = ref(0)
    const add = () => {
      num.value++
    }
    </script>
    
    <template>
      <div class="freestyle">我就是FreeStyle组件 Yoo</div>
      <button class="btn" @click="add">{{ num }}</button>
    </template>
    
    <style>
    .freestyle {
      color: blue;
      font-size: 24px;
      font-weight: 600;
    }
    .btn {
      width: 50px;
      height: 50px;
      border: 1px solid green;
    }
    </style>
    
  • .vitepress/theme/index.ts中注册FreeStyle.vue组件

import Theme from 'vitepress/theme'
import './style/var.css'
import FreeStyle from '../components/FreeStyle.vue'

export default {
  ...Theme,
  enhanceApp({ app }) {
    app.component('FreeStyle', FreeStyle)
  }
}
  • 在首页index.md使用组件
---
layout: home

hero:
  name: VitePress-Fun
  text: VitePress趣玩系列
  tagline: Lorem ipsum...
  image:
    src: /cat.png
    alt: VitePress
  actions:
    - theme: brand
      text: Get Started
      link: /guide/what-is-vitepress
    - theme: alt
      text: View on GitHub
      link: https://github.com/vuejs/vitepress

features:
  - icon: ⚡️
    title: Vite, The DX that can't be beat
    details: Lorem ipsum...
  - icon: 🖖
    title: Power of Vue meets Markdown
    details: Lorem ipsum...
  - icon: 🛠️
    title: Simple and minimal, always
    details: Lorem ipsum...
---

<div class="freestyle" style="color: red; font-size: 24px;">这是个有style的随便写点</div>
<FreeStyle></FreeStyle>

image.png

可以看到FreeStyle组件成功被渲染出来,并且点击按钮能响应式变化数字

所以,对于复杂的交互组件,我们可以通过自定义SFC,然后在theme/index.ts中注册组件,并在md中使用组件,达到想要的复杂交互效果

使用首页预留插槽

现在我们已经能做到在Features下Footer上添加自定义内容了,但是我有办法将自定义内容加到Header下Hero上吗

答案是可以的,vitepress首页给我们预留了很多插槽,通过插槽我们可以将自定义组件渲染到想要的位置

使用插槽案例

我们尝试将一个组件放到Hero上方

  • components目录下新建HeroBefore.vue
<script setup lang="ts"></script>

<template>
  <div class="before">HeroBefore</div>
</template>

<style>
.before {
  color: green;
  font-size: 24px;
  font-weight: 700;
  text-align: center;
}
</style>
  • 安装vue,因为需要使用vue提供的h方法
pnpm add vue -D
  • theme/index.ts中使用插槽
import Theme from 'vitepress/theme'
import './style/var.css'
import FreeStyle from '../components/FreeStyle.vue'
import { h } from 'vue'
import HeroBefore from '../components/HeroBefore.vue'

export default {
  ...Theme,
  Layout() {
    return h(Theme.Layout, null, {
      'home-hero-before': () => h(HeroBefore)
    })
  },
  enhanceApp({ app }) {
    app.component('FreeStyle', FreeStyle)
  }
}

image.png

可以看到组件已经渲染到Header下Hero上方了

查看插槽位置

vitepress文档并没有详细说明,我们可以通过查阅vitepress源码来知道预留的插槽位置,文件在src/client/theme-default/components/Layout.vue

<template>
  <div class="Layout">
    <slot name="layout-top" />
    <VPSkipLink />
    <VPBackdrop class="backdrop" :show="isSidebarOpen" @click="closeSidebar" />
    <VPNav>
      <template #nav-bar-title-before><slot name="nav-bar-title-before" /></template>
      <template #nav-bar-title-after><slot name="nav-bar-title-after" /></template>
      <template #nav-bar-content-before><slot name="nav-bar-content-before" /></template>
      <template #nav-bar-content-after><slot name="nav-bar-content-after" /></template>
      <template #nav-screen-content-before><slot name="nav-screen-content-before" /></template>
      <template #nav-screen-content-after><slot name="nav-screen-content-after" /></template>
    </VPNav>
    <VPLocalNav :open="isSidebarOpen" @open-menu="openSidebar" />
    <VPSidebar :open="isSidebarOpen" />

    <VPContent>
      <template #home-hero-before><slot name="home-hero-before" /></template>
      <template #home-hero-after><slot name="home-hero-after" /></template>
      <template #home-features-before><slot name="home-features-before" /></template>
      <template #home-features-after><slot name="home-features-after" /></template>

      <template #doc-footer-before><slot name="doc-footer-before" /></template>
      <template #doc-before><slot name="doc-before" /></template>
      <template #doc-after><slot name="doc-after" /></template>

      <template #aside-top><slot name="aside-top" /></template>
      <template #aside-bottom><slot name="aside-bottom" /></template>
      <template #aside-outline-before><slot name="aside-outline-before" /></template>
      <template #aside-outline-after><slot name="aside-outline-after" /></template>
      <template #aside-ads-before><slot name="aside-ads-before" /></template>
      <template #aside-ads-after><slot name="aside-ads-after" /></template>
    </VPContent>

    <VPFooter />
    <slot name="layout-bottom" />
  </div>
</template>

通过插槽名能大概猜到位置在哪,当然也能一个个试知道具体位置,结合这些插槽就能自定义出更个性化的vitepress首页了

使用插槽原理

重点是vue3提供的h函数

image.png

在官方文档的这篇文章中讲到,第三个参数传入一个对象,就表示给第一个参数,也就是render的组件的插槽传入内容

image.png

这个是vitepress默认使用的theme配置,当用户自定义了theme/index.ts的时候,就会优先使用用户配置,所以当我们传入Layout属性的时候,最终渲染的是我们传入的Layout,所以用h函数改写Layout并使用插槽,就能实现个性化首页