4.主题魔改说明
4.主题魔改说明
整个站站点的修改分为以下几个部分
插件式美化
src/.vuepress/client.ts
文件内容
import { defineClientConfig } from 'vuepress/client';
import { onMounted } from 'vue';
import { defineAsyncComponent } from 'vue';
import('./components/PrintVersion').then((res) => {
res.default();
});
const MyIcon = defineAsyncComponent(() => import('./components/MyIcon.vue'));
const TopNavBeautify = defineAsyncComponent(() => import('./components/TopNavBeautify.vue'));
const NavMusic = defineAsyncComponent(() => import('./components/NavMusic.vue'));
const CommentHideBtn = defineAsyncComponent(() => import('./components/CommentHideBtn.vue'));
const BlogBg = defineAsyncComponent(() => import('./components/BlogBg.vue'));
const PreviewImage = defineAsyncComponent(() => import('./components/PreviewImage.vue'));
const HeroContent = defineAsyncComponent(() => import('./components/HeroContent.vue'));
const HeroBG = defineAsyncComponent(() => import('./components/HeroBG.vue'));
const Hitokoto = defineAsyncComponent(() => import('./components/Hitokoto.vue'));
export default defineClientConfig({
enhance({ app, router, siteData }) {
app.component('MyIcon', MyIcon);
},
setup() {
onMounted(() => {});
},
rootComponents: [
TopNavBeautify,
NavMusic,
CommentHideBtn,
BlogBg,
PreviewImage,
HeroBG,
HeroContent,
Hitokoto,
// ...
],
});
插件源码都在 Github 上,可以自行查看:
https://github.com/mo7cc/blog-source/tree/main/src/.vuepress/components
每个插件都代表了某一个部分的美化效果,每个插件都是可以单独使用的。
插件功能说明
TopNavBeautify
: 顶部导航栏相关的美化。包括透明导航栏;侧边栏和导航栏一起上划隐藏,下划显示;简化搜索按钮;导航栏文字和图标颜色调整等。
HeroBG
: 博客首页的背景美化,这里是请求了自己的 bing 壁纸 api,每日自动更新。
HeroHitokoto
: 博客首页一言的美化,之前是会自动打字机切换,觉得挺烦的,就换成了现在的刷新更换。但是保留了打字机效果。
NavMusic
: 导航栏最右侧的音乐按钮,点击之后显示全局的音乐播放器,是使用 APlayer
音乐插件自己封装的。实现思路就是使用 js 强行在导航栏插入一片区域用于放置播放器。
CommentHideBtn
: 评论区的显示和隐藏按钮,默认是隐藏评论区的,当有留言需要的时候点击按钮显示评论区。
BlogBeautify
: 做了一些相关的主题的细节美化,包括文章分割线小汽车等,基本全是 css 效果。使用 vue 插件实现着扩展方便。
BlogBg
: 背景美化,让整个博客可以添加自定义的背景,让观感更加舒适。包括 sidebar 的毛玻璃效果等。还有内容部分的视觉优化。
每个插件都是覆盖式的,不会对主题原本造成任何影响。引入对应的组件,则效果就有,去除引用则效果消失。而且组件基本上都只在客户端生效,对原本的 SEO 以及编译过程没有任何影响,非侵入式的修改。主题无论如何更新迭代,都不会有什么影响,安全无公害,兼容性好。
插件的实现思路: 使用 css 覆盖主题原本的 css 效果。如果需要的 dom 结构主题没有,则采用 js 进插入,创造和修改。js 部分的修改全都是在原本的页面渲染完成之后异步进行的,所以仅仅只是观感上的修改而已,不会影响编译结果。
比如 一言插件 和 音乐插件 以及 背景插件,就是采用 js 异步创建 dom 实现的。
一些其余的效果
src/.vuepress/styles/index.scss
文件中
@import '@src/.vuepress/styles/bounce-icon.scss';
// place your custom styles here
.none {
width: 0;
height: 0;
user-select: none;
pointer-events: none;
overflow: hidden;
display: none;
}
// 自定义的页脚
.vp-footer-wrapper {
.vp-footer {
display: flex;
}
.mo7-footer-icp {
font-size: 14px;
display: flex;
align-items: center;
justify-content: center;
color: inherit;
& > img {
width: 14px;
margin-right: 4px;
}
}
.mo7-footer-about {
padding: 2px 3px;
border-radius: 3px;
position: relative;
color: inherit;
&:hover {
background-color: rgba($color: #0c7bf4, $alpha: 0.8);
color: #fff;
}
}
}
// 让内容在更宽的屏幕上可以有更宽的显示区域,嗯,宽屏补丁。
:root {
--content-width: 830px;
}
@media screen and (min-width: 1770px) {
:root {
--content-width: calc(100vw - 15rem - 6rem - var(--sidebar-width) - 20rem);
}
}
// 图片合组
.ImgGroup {
display: flex;
align-items: center;
justify-content: flex-start;
align-content: baseline;
width: 100%;
figure {
margin: 2px;
}
}
// 字体
@font-face {
font-family: 'mo7_font';
src: url('/font/mo7_font.ttf');
}
.vp-blog-hero-title,
.vp-site-name {
font-family: 'mo7_font';
}
// 回到顶部按钮半透明
.vp-back-to-top-button {
opacity: 0.7;
}
// 项目卡片添加阴影
.vp-project-card {
box-shadow: 0 2px 6px 2px var(--vp-c-shadow);
&:hover {
box-shadow: 0 1px 3px 1px var(--vp-c-shadow);
}
}
// 文章分割线变成小汽车
hr {
position: relative;
margin: 0.8rem auto;
box-sizing: content-box;
overflow: visible;
height: 1rem;
border: none;
cursor: pointer;
background: transparent;
&::before {
position: absolute;
bottom: 0;
left: 0;
z-index: 1;
content: '';
width: calc(100% - 0.25rem);
height: 0;
border-width: 0.125rem;
border-style: dashed;
opacity: 0.2;
}
&::after {
position: absolute;
line-height: 1.6rem;
top: -0.4rem;
left: 1%;
font-family: 'iconfont';
content: '\e66c';
z-index: 2;
font-size: 1.6rem;
transition: 1s;
opacity: 0.2;
}
&:hover {
&::after {
opacity: 0.8;
left: calc(99% - 1.6rem);
}
}
}
// 美化标签hover之后的小标签
[aria-label][data-balloon-pos]:after {
border-radius: 0.6rem;
}
[aria-label][data-balloon-pos]:hover:before,
[aria-label][data-balloon-pos]:hover:after,
[aria-label][data-balloon-pos][data-balloon-visible]:before,
[aria-label][data-balloon-pos][data-balloon-visible]:after,
[aria-label][data-balloon-pos]:not([data-balloon-nofocus]):focus:before,
[aria-label][data-balloon-pos]:not([data-balloon-nofocus]):focus:after {
opacity: 0.8;
font-family: none;
}
// 卡片半透明
@mixin articleLightBg {
$my-alpha: 0.6;
background: rgba($color: #fff, $alpha: $my-alpha);
background-color: rgba($color: #fff, $alpha: $my-alpha);
}
[data-theme='light'] {
.theme-container {
.vp-page {
.vp-blogger-info {
@include articleLightBg;
}
.vp-blog-infos {
@include articleLightBg;
}
.vp-article-item {
@include articleLightBg;
}
}
.vp-pagination-nav input {
@include articleLightBg;
}
.vp-pagination-button {
@include articleLightBg;
}
.vp-pagination-number div {
@include articleLightBg;
&.active {
background-color: var(--theme-color);
}
}
}
}
@mixin articleDarkBg {
$my-alpha: 0.7;
background: rgba($color: #000, $alpha: $my-alpha);
background-color: rgba($color: #000, $alpha: $my-alpha);
}
[data-theme='dark'] {
.theme-container {
.vp-page {
.vp-blogger-info {
@include articleDarkBg;
}
.vp-blog-infos {
@include articleDarkBg;
}
.vp-article-item {
@include articleDarkBg;
}
.vp-pagination-nav input {
@include articleDarkBg;
}
.vp-pagination-button {
@include articleDarkBg;
}
.vp-pagination-number div {
@include articleDarkBg;
&.active {
background-color: var(--theme-color);
}
}
}
}
}