100 lines
8.8 KiB
Markdown
100 lines
8.8 KiB
Markdown
|
---
|
|||
|
{
|
|||
|
title: "建站小记",
|
|||
|
description: "作者选择自行搭建博客以挑战技术能力,追求完全控制权。项目使用Nuxt(Content + SSG)、TypeScript、Tailwind CSS等技术栈,开发中遇到Nuxt ColorMode切换动画问题、Content的Schema类型难题以及响应式布局与动画冲突等挑战。目前进度不理想,管理端尚未完成,能否完工取决于后续时间。",
|
|||
|
draft: false,
|
|||
|
type: "article",
|
|||
|
created_at: "2025-08-25T02:54:33+08:00",
|
|||
|
published_at: "2025-08-25T04:17:34+08:00",
|
|||
|
updated_at: [ "2025-08-25T02:54:33+08:00" ],
|
|||
|
category: '记录',
|
|||
|
tags: [ "前端", "文档" ],
|
|||
|
tech_stack: [ "Vue.js","Nuxt","TypeScript" ],
|
|||
|
tech_stack_percent: [ 60,70,40 ],
|
|||
|
tech_stack_icon_names: [ "mdi:vuejs","lineicons:nuxt", "lineicons:typescript" ],
|
|||
|
tech_stack_theme_colors: [ "#41b883", "#a179dc", "#054e63" ],
|
|||
|
}
|
|||
|
---
|
|||
|
## 为什么我要自行建设博客?
|
|||
|
> We choose to go to the moon in this decade and do the other things, not because they are easy, but because they are hard; because that goal will serve to organize and measure the best of our energies and skills, because that challenge is one that we are willing to accept, one we are unwilling to postpone, and one which we intend to win, and the others, too.
|
|||
|
> —— John F. Kennedy, 1962
|
|||
|
> 我们选择在这个十年内登上月球并完成其他任务,不是因为它们容易,而是因为它们困难;因为这个目标将有助于组织和衡量我们最好的精力和技能,因为这是一个我们愿意接受的挑战,一个我们不愿推迟的挑战,一个我们打算赢得的挑战,当然也包括其他挑战。
|
|||
|
> —— 约翰·F·肯尼迪,1962年
|
|||
|
|
|||
|
从某种程度上来说,我自行搭建博客的原因与以上发言类似 ~~(有点大言不惭了)~~ ,我需要一个测试自己的机会。我已经构建了几十个项目,我对它们尽心尽力,但是它们中大多数生命周期很短,往往是为了实验、比赛等短期目标。这些代码往往不需要过高的可扩展性和稳定性。同时,我注意到我的能力似乎已经足以支撑我去构建一个更加大型的长期项目。思来想去,博客是一个不错的选择,并且我可以通过它来记录我的学习和生活。
|
|||
|
|
|||
|
构建博客的原因之二是,市面上现有的博客也许它们能满足我的需求,但是我感觉研究它们的配置没有我自己重写一个有趣。而且,我希望能够完全控制我的博客内容和样式,而不是被平台所限制。
|
|||
|
|
|||
|
## 进展如何?
|
|||
|
当我实际开始写之后,我注意到这件事远比我设想的复杂。有很多技术我只是想当然的认为可行,虽然结果也确实能行,但是有大量的细节需要注意。不得不说,首次编写本博客的现在已是暑假之末,但是项目进度很不理想。先不考虑管理端,博客部分有两个页面没创建,一个页面有bug,已有页面中有一个组件还没开始写。
|
|||
|
|
|||
|
而管理端前后端呢?更是不见踪影,与博客配对的相关配置,也处于残缺状态。
|
|||
|
|
|||
|
考虑到后续的比赛、保研以及可能的实习。我只能说,这项目能不能写完纯看缘分。
|
|||
|
|
|||
|
## 博客技术
|
|||
|
聊点不那么现实的
|
|||
|
|
|||
|
这次博客使用了Nuxt来编写,Nuxt构建后的产物的加载速度给我留下了颇为深刻的印象。在与ChatGPT、Claude 聊了一段时间后,确定了用Nuxt Content + SSG作为博客核心。
|
|||
|
|
|||
|
就目前的开发体验来说,Nuxt的启动和加载确实不够快,但是其代码确实足够优雅,我很喜欢。虽然从一定角度来讲,为了所谓的优雅,牺牲了太多开发效率,消耗了太多时间在查文档和debug上。 但是我觉得这是值得的。从某种程度而言,我学计算机就是想来干这个的。
|
|||
|
|
|||
|
对于其他的技术栈,目前博客使用了
|
|||
|
```Text
|
|||
|
TypeScript
|
|||
|
Pinia
|
|||
|
Tailwind CSS
|
|||
|
Nuxt UI
|
|||
|
HighCharts
|
|||
|
MdEditor V3
|
|||
|
```
|
|||
|
那些大家都在用的就不放了
|
|||
|
|
|||
|
这里面 TypeScript Tailwind CSS 能明显提升前端体验,我说实话,我已经不太确定自己能不能写纯CSS项目了,TS更不用多说,JS看了半小时我就开始用TS了。好用爱用。
|
|||
|
|
|||
|
在用Nuxt时,顺便被安利了Nuxt UI 就目前来讲,还可以,用的没有TDesign熟练,有些组件即便有还是选择了手搓,主要还是控制上差了一点。这次没用TDesign主要是和博客想要的风格不符,TDesign有点太正式了。ElementPlus也不考虑,有点丑,我用的也少。
|
|||
|
|
|||
|
Nuxt的Pinia集成也是一个难点,曾几何时,Nuxt的Pinia集成搞了我一下午的时间。Vuex还没学过,我估计这个项目也不需要,Pinia够了。
|
|||
|
|
|||
|
HighCharts是个意外,我本来想用ECharts的,但是ECharts不支持坐标轴中放HTML代码,只支持纯文字。而HighCharts虽然也不是能接受任意HTML,但至少支持svg。配合[icons](https://icones.js.org/)这个强大的网站,够用了。
|
|||
|
HighCharts开源但商用收费,拿来建个人博客还是没问题的。
|
|||
|
PS:HighCharts的介绍页面图表又多又好看,期待后续有新想法继续使用。
|
|||
|
|
|||
|
MdEditor V3 这是我第一个使用的前端Markdown编辑/渲染器。之前做实验就用过,但是这次我没有首选它,而是选了MilkDown,不好用。
|
|||
|
从 MilkDown core 和 MilkDown creep 中可以看到这个项目的潜力。但是实在有点难配了,文档真看不懂,感觉写的有点屎,当然我觉得还是自己能力不足。只能说为了WYSIWYG实在不值得,双屏写MD我是没什么障碍的,例如我现在就在WebStorm里写MD,然后同步渲染到dev网页里。因此索性放弃了MilkDown。
|
|||
|
后来又试了 Markdown-it。如果我没记错,放弃它的原因是因为滚动不是连贯的。
|
|||
|
|
|||
|
试来试去,发现最初遇到的就是最好的,果断复合了。
|
|||
|
|
|||
|
PS:正在写这篇文章的时候,发现上面的代码段竟然在我Navbar的上面,一看z-index是10000,绝了。改成5了,我看看会出什么问题。
|
|||
|
|
|||
|
## 遇到的各种难点
|
|||
|
### Nuxt ColorMode
|
|||
|
这个插件真的很神奇。如果我没记错,这个插件的问题是在切换主题时,有些设置了过渡动画的DOM没有播放动画,而是一步到位。我真的卡了很久,但最后没办法,自己实现了一个ColorMode切换器,丝滑无比。而且我认为原理上和Nuxt-ColorMode应该是一致的,都是在顶级中添加dark class。但是用这插件就是会出现问题,最终含泪放弃。
|
|||
|
### Nuxt Content
|
|||
|
Nuxt Content 的文档确实需要仔细翻才能找到某些功能。从某种程度上也是吃了英语不好的亏。但总体来说,这个手册质量还是在线的。
|
|||
|
但是我也确实有没能解决的问题。
|
|||
|
|
|||
|
Content Config 中有一个 Schema 的属性,它会利用zod,自动生成一个ContentCollectionItem属性。Schema作用是定义文章元数据,如果定义了rawbody,那么将得到文章原文。
|
|||
|
问题出在 queryCollection 后的 select 方法上,select方法接受一组键,这些键都是Schema中定义的数据结构,但是问题在于,我只是不想要其中的rawbody,因为在列表加载原文可能会浪费很多性能。
|
|||
|
在这种情况下,我希望将 Schema 提取出来,然后将所有非rawbody的键写入到select中。这么做虽然没问题,但是TS不高兴。虽然我们通过 Schema 定义了 文章属性,但是它与自动生成 ContentCollectionItem 毫无关联。对于ts来说,我们在试图将string赋值给keyof ContentCollectionItem,这显然是不行的。
|
|||
|
而ContentCollectionItem也没有export出来,无法直接使用。
|
|||
|
目前的解决方案是,先连同rawbody一起加载,出问题再说。理论上,只有生成时会慢,运行时不会受影响。
|
|||
|
|
|||
|
### 粘性布局、响应式更新与动画冲突
|
|||
|
这三个东西随便缺一个都不会有我接下来要讲的神奇问题
|
|||
|
在浏览其他人的博客时,我注意到大部分博客信息流旁会有一个随滚动而滚动的侧边栏,这个侧边栏通常是粘性布局实现的。
|
|||
|
|
|||
|
但我在具体实现上犯了难。
|
|||
|
|
|||
|
观察别人的博客HTML后,确定应当将sticky的父设置为table,然后把sticky DOM设置为float left,主DOM设置为 float right。这样,粘性布局就搞定了。
|
|||
|
|
|||
|
在其基础上,设置断点对应的宽度,实现响应式布局,也没问题。
|
|||
|
|
|||
|
再加上动画设置,结果问题出现了。
|
|||
|
|
|||
|
由于使用了浮动,而两个DOM都是块。当两者宽度大于父DOM宽度时,两个DOM会从左右布局变为上下布局。在动画开始时是正确的,动画结束时是正确的,但是动画进行时,外部的DOM宽度减小速度过快,内部的宽度减小速度较慢,导致内部两DOM变为上下布局。
|
|||
|
|
|||
|
解决方法是:把原先会响应式更新的侧边栏的宽度改为固定值,然后让右侧DOM根据父组件计算自己的宽度。这样就不会出现上述问题了。
|
|||
|
## 未完待续
|
|||
|
最近保研真是焦虑quq
|