开发技巧
介绍 Teek 开发路程的一些技巧。
规范
Teek 建议在进行项目开发时,一个文件的代码行数推荐 300 行以下,最好不超过 500 行,禁止超过 1000 行。
如果超过 300+ 行,应该考虑下是否可以拆分为多个文件,这是一个良好的 结构化思维和分治思维。
提示
Teek 建议您在开发前先思考有哪些模块,然后分别创建模块文件,而不是先在一个文件写完,再拆分。
举个例子:
代码合在一个文件:
<div><divclass="header"><imgsrc="logo.png"/><h1>网站名称</h1></div><divclass="main-content"><divclass="banner"><ul><li><imgsrc="banner1.png"/></li><!-- 省略n行代码 --></ul></div><divclass="post-list"><!-- 省略n行代码 --></div><!-- 省略n行代码 --></div></div>
将代码进行模块化,根据功能/布局/逻辑等进行拆分:
<div><header/><main><Banner/><PostList/><Card/><AboutMe/></main><footer/></div>
假设您没有参与过该项目开发,现在由您来开始开发 PostList
模块的功能,我相信您更喜欢第二种,因为它已经明确的在向您挥手。
SSR 兼容
在 VitePress 主题开发时,请考虑 SSR 兼容性。否则在构建项目时,报错:window/document is not defined
。
关于 SSR 兼容性,VitePress 官方提供了 SSR 兼容性的文档可以参考,文档里介绍了几个方式如何兼容 SSR。
但是 Teek 在这里提供一个 VitePress 官方没有 直接说明的一种方式,这也是 Teek 兼容 SSR 的方式,即:
在任何访问浏览器或调用 DOM API 的代码前加上 SSR 环境校验。
首先自定义一个 SSR 环境检验变量:
constisClient=typeofwindow !=="undefined"&&typeofdocument !=="undefined";
然后在使用 DOM API 之前加上这个校验,这样就防止构建时报错:
<scriptsetuplang="ts">import{isClient } from"vitepress-theme-teek";constinit=() =>{if(!isClient) return;constxxDom=document.querySelector(".xx");};init();</script><template></template>
如果您的代码在 Vue 组件的 beforeMount
或 mounted
钩子中执行,则无需考虑 SSR,Vue 已经处理了。
利用对象/数组减少 HTML 编写
对象形式
在 template
用 if
、if-else
判断。
<scriptsetuplang="ts">import{A,B,C,D } from"./components";import{useData } from"vitepress";const{theme} =useData();constprovider=theme.value.provider;</script><template><templatev-if="provider ==='a'"name="a"><A/></template><templatev-else-if="provider ==='b'"name="b"><B/></template><templatev-else-if="provider ==='d'"name="c"><C/></template><templatev-else-if="provider ==='d'"name="d"><D/></template></template>
可以将其转为对象:
<scriptsetuplang="ts">import{A,B,C,D } from"./components";import{useData } from"vitepress";const{theme} =useData();constprovider=theme.value.provider;constproviderMap={a:{el:A,props:{name:"a"} },b:{el:B,props:{name:"b"} },c:{el:C,props:{name:"c"} },d:{el:D,props:{name:"d"} },};</script><template><componentv-if="provider":is="providerMap[provider]?.el"v-bind="providerMap[provider]?.props"/></template>
可以在组件 Layout的评论区相关代码或者 HomeBanner查看具体使用。
数组形式
在 template
编写类似的重复 HTML。
<scriptsetuplang="ts"></script><template><div><div><spanclass="title">A</span><spanclass="desc">测试 A</span></div><div><aclass="link"href="/b">B</a><spanclass="desc">测试 B</span></div><div><imgclass="link"src="/c.png"/><spanclass="desc">测试 C</span></div></div></template>
可以将其转为数组:
<scriptsetuplang="ts">constlist=[{title:"A",desc:"测试 A",className:"title"},{title:"B",desc:"测试 B",isLink:true,className:"link",link:"/b"},{desc:"测试 C",isImg:true,className:"img",link:"/c.png"},];</script><template><div><divv-for="item in list":key="item.title"><av-if="item.isLink":class="item.className":href="item.link">{{item.title }}</a><imgv-else-if="item.isImg":class="item.className":src="item.link"/><spanv-else:class="item.className">{{item.title }}</span><spanclass="desc">{{item.desc }}</span></div></div></template>
仅限于重复度接近 90% 以上或者简单的 HTML,否则不建议使用数组 + for
循环,可读性会变差。
可以在组件 ArticleInfo查看具体使用。
配置项支持方式
config 配置
如果配置项仅支持在 .vitepress/config.mts
配置:
在组件里这样使用:
<scriptsetuplang="ts">import{useData } from"vitepress";const{theme} =useData();const{enabled=true,name="",obj={},arr=[] } ={...theme.xxx };</script><template></template>
这样避免了获取 theme.xxx
里的属性时报 undefined
(没配置 xxx
),同时如果 theme.xxx
里的某些属性没有配置,则赋予默认值。
config 和 frontmatter 配置
配置项同时支持在 .vitepress/config.mts
和 Markdown 的 frontmatter
配置,当两种都配置,则以 frontmatter
为准。
在组件里这样使用:
<scriptsetuplang="ts">import{computed } from"vue";import{useData } from"vitepress";const{theme,frontmatter} =useData();constthemeConfig=computed(() =>({enabled:true,name:"",obj:{},arr:[],...theme.xxx,...frontmatter.value.xxx,...frontmatter.value.tk.xxx,}));console.log(themeConfig.value.xxx);</script><template></template>
frontmatter.value.tk.xxx
是在首页 index.md
配置 frontmatter
时,额外添加了 tk
,这是为了避免与 VitePress 自带配置的命名冲突。
支持 frontmatter
配置时,一定要用 computed
监听 frontmatter
变化,因为不同 Markdown 的 frontmatter
有可能不一样,如果没有监听 frontmatter
变化,会导致切换 Markdown 文章后,新文章的配置不会重新生效。
如:
import{defineTeekConfig } from"vitepress-theme-teek/config";constteekConfig=defineTeekConfig({comment:{provider:"giscus",options:{repo:"your repo",repoId:"your repoId",category:"your category",categoryId:"your categoryId",}};});
---tk:comment:provider:"giscus"options:repo:"your repo"repoId:"your repoId"category:"your category"categoryId:"your categoryId"---
---comment:provider:"giscus"options:repo:"your repo"repoId:"your repoId"category:"your category"categoryId:"your categoryId"---