我正在参加「掘金·启航计划」
尝试开一个vitepress趣玩系列,讲一下我看到的比较有意思的vitepress玩法
上一篇文章vitepress趣玩系列——首页样式优化,我们把基本的首页内容已经完成了,还没工程的推荐先看第一篇文章,接下来做一些更有意思的处理,让首页的内容更丰富
灵感
偶然一天在看vite文档,看到它的文档也是用的vitepress设计,但会比其他的vitepress首页内容会更丰富
这是普通的
这是vite的
可以看到,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: '那我就随便写个吧',
}
}
})
可以看到底部已经有注脚了
首页组件
如果我们觉得首页内容比较单调,想自己设计点可交互的内容,我们可以通过以下方案
方案一,直接写在首页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...
---
随便写点内容
添加的内容是能直接渲染到首页的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>
我们尝试着加点class属性,让内容更丰富
可以看到,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>
可以看到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)
}
}
可以看到组件已经渲染到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函数
在官方文档的这篇文章中讲到,第三个参数传入一个对象,就表示给第一个参数,也就是render的组件的插槽传入内容
这个是vitepress默认使用的theme配置,当用户自定义了theme/index.ts
的时候,就会优先使用用户配置,所以当我们传入Layout属性的时候,最终渲染的是我们传入的Layout,所以用h函数改写Layout并使用插槽,就能实现个性化首页