前言
虽然Vuepress 的vuepress-theme-reco
主题已经很完美了,为了更加适合自己,终究还是逃不过我一颗想要魔改的心,魔改主题欢乐多:
更换主题到本地后,无法直接通过npm install 直接更新主题
侧边栏优化,右侧滚动栏优化,字体优化
增加各种好玩实用的插件
更换主题为本地
与hexo不一样,正常的主题文件会被安装到node_modules
文件夹中。如果之前vuepress-theme-reco
安装正确的话,可以在node_modules
文件夹中找到改文件。所以如果不把主题文件放到本地,我们每次执行npm install 的时候,新的文件就会把我们魔改过的文件覆盖掉。
接着不得不谈一下主题的启动流程:如果config没指定,系统会默认会检查.vuepress/theme
,如果还没有就,直接用默认主题。
所以只要把下载(或者直接从node_modules
中复制)下来的文件夹更名为theme ,粘贴至 .vuepress文件夹下即可,如果在执行编译过程中,看到tip Apply local theme at xxx\Desktop\blog\.vuepress\theme...
相关提示,就说明从theme文件夹启动成功
整个目录结构如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Dev ├─── docs │ └── .vuepress // 配置目录 │ │ ├── public // 静态资源 │ │ ├── theme // 主题 │ │ │ ├── components // 组件 │ │ │ ├── global-components // 全局组件 │ │ │ ├── layouts // 布局(包括首页在内) │ │ │ ├── styles // 样式 │ │ │ ├── util // 工具 │ │ │ ├── index.js // 入口配置 │ │ │ ├── noopModule.js // 依赖注入 │ │ │ ├── package .json // 主题依赖 │ │ │ ├── README.md // 主题说明 │ │ └── config .js │ ├── FAQ // 求索模块 │ ├── Store // 仓库模块 │ ├── Thought // 随笔模块 │ └── README.md // 博客首页 └── package .json
外挂组件修改
如果你不满足于主题提供的默认样式,VuePress 提供了一些简单的接口文件,可以让你能够很方便地定制你自己想要的效果,和hexo外挂组件修改 一样,这类修改无需改动源码 ,上手简单。
修改主题颜色
我这里暂时没有修改,如有需要可以通过配置 .vuepress/styles/palette.styl
来快速修改主题的一些颜色属性。(如果不存在该目录和文件就创建一个)
1 2 3 4 5 6 $accentColor = #3eaf7c $textColor = #2c3e50 $borderColor = #eaecef $codeBgColor = #282c34 $backgroundColor = #ffffff
修改主题样式
你可以创建一个 .vuepress/styles/index.styl
文件以方便地添加额外样式。这是一个 Stylus 文件,但你也可以使用正常的 CSS 语法,我的修改如下,主要是改进了文档页面的可读性和操作性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 .sidebar > .sidebar-links > li > a .sidebar-link { font-size : 1.5em !important; margin-left : -1em ; } a .sidebar-link { font-size : 16px !important; } .sidebar-heading span{ font-size : 1.2em ; font-weight : bold; } .sidebar-heading .open span{ font-weight : bold; } a .sidebar-link .active { color : #070808 !important; font-size : 14px !important; background : #c3d4b7 42 !important; } .sidebar-sub-headers a .sidebar-link { margin : 0 1rem 0 1rem !important; } .sidebar-group .is-sub-group > .sidebar-heading :not(.clickable){ opacity : 0.5 ; } .page .page-title { display : none; }
效果如下
其他修改,主要参照znote大佬 ,修改如下(可选):
需要的点击打开
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 blockquote { background-color : transparent !important; margin : 20px !important; padding : 0 !important; font-size : 1rem !important; color : #999 !important; border-left: .25rem solid #dfe2e5 !important; margin-left : 0 !important; padding-left : 1rem !important; } .custom-block .tip { background-color : #d4d4d4 52 !important; } .custom-block .warning { background-color : #ffa16d 47 !important; } .custom-block .danger { background-color : #f9b4b4 57 !important; } summary { font-weight : 550 ; font-size : 16px ; margin-top : 0.2rem ; padding-top : 11px ; padding-bottom : 11px ; background-color : #75826b 42; border-radius : 5px ; } .timeline-wrapper .year { margin : 80px 0px 20px !important; font-size : 27px !important; } .timeline-wrapper .year-wrapper li { padding : 10px 20px 10px !important; border-bottom : 2px solid #999da0 6b !important; background : #c1c1e6 26; border-radius : 5rem ; margin : 5px 0px ; transition: all .5s; } .timeline-wrapper .year-wrapper li :hover { transform : translate(50px ,0 ); transition: all .5s; } .timeline-wrapper .year-wrapper li .date { width : 43px !important; font-size : 13px !important; } .timeline-wrapper .year-wrapper li .date :before { top : 22px !important; border : 1px solid !important; } .timeline-wrapper :after { background : skyblue !important; } .timeline-wrapper .desc :before, .timeline-wrapper .year :before { background : cadetblue !important; } .page , .password-wrapper-in { margin-left : 8rem !important; } .comments-wrapper { padding : 2rem 2rem 2rem 10rem !important; } #valine .vwrap .vedit #veditor{ background : url('/znote/img/other/comment.png' ) background-position : 90% 60% background-size : 16rem 10rem background-repeat : no-repeat } $mobileSidebarWidth = $sidebarWidth * 0.82 @media (max-width : $MQNarrow ) .sidebar font-size 15px width $mobileSidebarWidth !important; .page , .password-wrapper-in margin-left $mobileSidebarWidth !important; .comments-wrapper padding : 2rem 2rem 2rem $mobileSidebarWidth *1.1 !important; @media (max-width : $MQMobile ) .sidebar top 0 padding-top $navbarHeight !important; transform translateX(-100% ) transition transform .2s ease .page , .password-wrapper-in margin-left 0 !important; .comments-wrapper padding : 2rem 2rem 2rem 2rem !important; .theme-container &.sidebar-open .sidebar transform translateX(0 ) !important; &.no-navbar .sidebar padding-top : 0 !important; .password-shadow padding-left 0 !important; @media (max-width : $MQMobileNarrow ) h1 font-size 1.9rem .content__default div [class*="language-" ] margin 0.85rem -1.5rem !important; border-radius 0 @media (min-width : ($MQMobile + 1px )) .theme-container .no-sidebar .sidebar display none .page , .password-wrapper-in margin-left 0 !important; .comments-wrapper padding : 2rem 2rem 2rem 2rem !important; .abstract-item { background-color : #acdcfd 3d !important; transition: all .5s; } .abstract-item :hover { transform : scale(1.02 ); transition: all .5s; } ::-webkit-scrollbar width : 6px !important; ::-webkit-scrollbar-thumb { background-color :#94989c 8c !important; background-clip :padding-box !important; -webkit-border-radius : 10em !important; -moz-border-radius : 10em !important; border-radius : 10em !important; } ::-webkit-scrollbar-track-piece { background-color :transparent !important; -webkit-border-radius : 0em !important; -moz-border-radius : 0em !important; border-radius : 0em !important; } ::-webkit-scrollbar-thumb:hover { background-color :#bbb !important; } .navbar .links font-size : 15.5px !important; .theorem margin 1rem 0 padding .1rem 1.5rem border-radius 0.4rem background-color #c9daea 61 .title font-weight bold .custom-block &.right color transparentify($textColor , 0.4 ) font-size 0.9rem text-align right @require './markdown-container'
这里作者还引入了markdown-container.styl ,需要的自行引入
需要的点击打开
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 .cardListContainer margin .7rem 0 &>:not(.card-list) display none .card-list margin -0.35rem display : flex; flex-wrap : wrap; align-items : flex-start; .card-item width calc(100%/3 - .7rem) margin auto background var(--bodyBg) border-radius 3px color var(--textColor) display flex box-shadow 1px 1px 2px 0 rgba(0,0,0,.06) &:hover text-decoration none img transform rotate(8deg ) scale(1.1 , 1.1 ) box-shadow 3px 2px 7px rgba(0 , 0 , 0 , 0.15 ) div p text-shadow 3px 2px 5px rgba(0 , 0 , 0 , 0.15 ) img width 60px height 60px border-radius 50% border 2px solid #fff margin 1rem margin-right 0 box-shadow 3px 2px 5px rgba(0 , 0 , 0 , 0.08 ) transition all .4s div flex 1 display inline-block float right padding 1rem 0 p margin 0 padding 0 1rem transition text-shadow .4s text-align center .name margin .2rem 0 .3rem 0 .desc font-size .8rem line-height 1.1rem opacity .8 margin-bottom .2rem .card-item .row-1 width calc(100% - .7rem) img margin-left 2rem .card-item .row-2 width calc(100%/2 - .7rem) img margin-left 1.5rem .card-item .row-3 width calc(100%/3 - .7rem) .card-item .row-4 width calc(100%/4 - .7rem) .cardImgListContainer margin 1rem 0 &>:not(.card-list) display none .card-list margin -0.5rem display : flex; flex-wrap : wrap; align-items : flex-start; .card-item width calc(100% /3 - 1rem ) margin .5rem background var(--mainBg) border 1px solid rgba(0 ,0 ,0 ,0.08 ) box-sizing : border-box border-radius 3px overflow hidden color var(--textColor) box-shadow 2px 2px 10px rgba(0,0,0,.04) display flex flex-direction : column; justify-content : flex-start; align-items : stretch; align-content : stretch; transition: box-shadow .3s &:hover box-shadow 1px 1px 20px rgba(0,0,0,.07) .box-img overflow hidden position relative background #000 img display block width 100% height auto transition: all .3s &:hover img transform : scale(1.1 , 1.1 ) opacity .75 a color var(--textColor) transition: color .3s &:hover color $accentColor text-decoration none .box-info padding: .8rem 1rem p margin 0 .desc margin-top: .3rem opacity .8 font-size: .9rem line-height : 1.1rem .box-footer overflow hidden padding: .8rem 1rem border-top : 1px solid rgba(0 ,0 ,0 ,0.05 ) img width 1.8rem height 1.8rem border-radius 50% float left span line-height 1.8rem float left margin-left: .6rem font-size: .8rem .card-item .row-1 width calc(100% - 1rem ) .card-item .row-2 width calc(100% /2 - 1rem ) .card-item .row-3 width calc(100% /3 - 1rem ) .card-item .row-4 width calc(100% /4 - 1rem ) .theme-mode-dark .cardImgListContainer .card-list .card-item border-color : var(--borderColor) .box-footer border-color : var(--borderColor) @media (max-width : 900px ) .cardListContainer .card-list .card-item .row-4 width calc(100%/3 - .7rem) .cardImgListContainer .card-list .card-item .row-4 width calc(100% /3 - 1rem ) @media (max-width : 720px ) .cardListContainer .card-list .card-item .row-3 , .card-item .row-4 width calc(100%/2 - .7rem) img margin-left 1.5rem .cardImgListContainer .card-list .card-item .row-3 , .card-item .row-4 width calc(100% /2 - 1rem ) @media (max-width : 500px ) .cardListContainer .card-list .card-item .row-1 , .card-item .row-2 , .card-item .row-3 , .card-item .row-4 width calc(100% - .7rem) img margin-left 1.5rem .cardImgListContainer .card-list .card-item .row-1 , .card-item .row-2 , .card-item .row-3 , .card-item .row-4 width calc(100% - 1rem )
不可以 将颜色与样式写在同一个文件中,VuePress 会先解析 palette.styl
中的全局变量,之后作用于主题的各个样式中,最后才解析 index.styl
,以覆盖主题默认的样式。
引用脚本与样式
操作说明
这个操作类似butterfly主题中的inject ,你可以通过配置 .vuepress/config.js
中的 head
来引入脚本与样式。
通过外挂css和js来对主题样式曾铁,例如点击效果,花瓣雨等等特效。
1 2 3 4 5 6 module .exports = { head: [ ["link" , { rel : "stylesheet" , href : "https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.css" }], ["script" , { src : "scripts/demo.js" }] ] }
比如上面的配置就会被解析为
1 2 3 4 <head > <link rel ="stylesheet" href ="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.css" > <script src ="scripts/demo.js" > </script > </head >
关于 head
的详细配置说明请参考官方文档 head 配置
引入鼠标点击效果
在.vuepress\public\js
文件夹下创建MouseClickEffect.js
文件,填入以下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 var a_idx = 0 ;function getRandom (max, min ) { return Math .floor(Math .random() * (max - min + 1 ) + min); } jQuery(document ).ready(function ($ ) { $("body" ).click(function (e ) { var a = new Array ("富强" , "民主" , "文明" , "和谐" , "自由" , "平等" , "公正" , "法治" , "爱国" , "敬业" , "诚信" , "友善" ); var $i = $("<span/>" ).text(a[a_idx]); a_idx = (a_idx + 1 ) % a.length; var x = e.pageX, y = e.pageY; $i.css({ "z-index" : 999999999999999999999999999999999999999999999999999999999999999999999 , "top" : y - 20 , "left" : x, "position" : "absolute" , "font-weight" : "bold" , "color" : `rgb(${getRandom(255 ,0 )} ,${getRandom(255 ,0 )} ,${getRandom(255 ,0 )} )` , "user-select" : 'none' , "cursor" : 'default' }); $("body" ).append($i); $i.animate({ "top" : y - 180 , "opacity" : 0 }, 1500 , function ( ) { $i.remove(); }); }); });
然后在主题配置文件config.js
下的head
引入以上js,这里的jquery必须引入,鼠标点击代码才能生效
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 head: [ ['link' , { rel : 'icon' , href : '/vuepress/favicon.ico' }], ['meta' , { name : 'viewport' , content : 'width=device-width,initial-scale=1,user-scalable=no' }], ["script" , { "language" : "javascript" , "type" : "text/javascript" , "src" : "https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js" }], ["script" , { "language" : "javascript" , "type" : "text/javascript" , "src" : "/js/MouseClickEffect.js" }] ],
文章中引入样式和脚本
有时,你可以只想在当前页面应用一些 JavaScript
或者 CSS
,在这种情况下,你可以直接在 Markdown
文件中使用原生的 或者 标签,它们将会从编译后的 HTML 文件中提取出来,并作为生成的 Vue 单文件组件的和标签。
输入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <p class ="demo" :class ="$style.example" > </p > <style module > .example { color : #41b883 ; } </style > <script > export default { props: ['slot-key' ], mounted () { document .querySelector(`.${this .$style.example} ` ) .textContent = '这个块是被内联的脚本渲染的,样式也采用了内联样式。' } } </script >
输出
这个块是被内联的脚本渲染的,样式也采用了内联样式。
推荐插件类
我的插件配置
所有插件必须要用中括号包起来 ,别问为啥,吃过苦头😵
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 module .exports = [ ['flowchart' ], ["vuepress-plugin-boxx" ], ["dynamic-title" , { showIcon: "vuepress/smile.ico" , showText: "(/≧▽≦/)欢迎帅哥美女!" , hideIcon: "vuepress/cry.ico" , hideText: "(●—●)呜呜,不要走嘛!!" , recoverTime: 2000 }], ['@vuepress/pwa' , { serviceWorker: true , updatePopup: { message: "发现新内容可用" , buttonText: "刷新" } }], ["vuepress-plugin-nuggets-style-copy" , { copyText: "复制代码" , tip: { content: "复制成功!" } }], ['meting' , { meting: { server: "netease" , type: "playlist" , mid: "696441716" , }, aplayer: { fixed: true , mini: true , autoplay: true , listFolded:true , theme: '#f9bcdd' , order: 'random' , volume: 0.1 , lrcType: 0 }, mobile :{ cover: false , } }] ]
音乐插件
目前音乐插件有两种:
bgm-player ,一款简洁易用的音乐插件,优势是好看,其他一无是处了🙂
music-bar ,一个程序猿自己开发的插件,除本地,网络音频之外还支持从平台歌单获取链接(目前仅支持网易云音乐),缺点是丑了点,支持一下这位老哥👯
meting ,在hexo上就一直用的插件,功能强大,配置丰富,目前应该最大强大的音乐插件了,我用的就是这个,强推👍,还支持在markdown中直接插入,操作如下
1 2 3 4 <Meting server="netease" type="playlist" mid="2539599584" :lrc-type="3"/>
这里再推荐一个音乐外链网:http://music.xf1433.com/
趣味标题插件
这个在hexo已经很熟悉了,主要在标签栏当时选中和离开页面时会有变化
安装
1 npm i vuepress-plugin-dynamic-title -D
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 module .exports = { plugins: [ [ "dynamic-title" , { showIcon: "/favicon.ico" , showText: "(/≧▽≦/)咦!又好了!" , hideIcon: "/failure.ico" , hideText: "(●—●)喔哟,崩溃啦!" , recoverTime: 2000 } ] ] }
Boxx插件
参考:https://zpj80231.gitee.io/znote/views/front-end/vuepress-plugin-boxx.html
可以为博客文章自动随机添加名人名言或其他,可自定义样式和内容
安装
在文件package.json
中的devDependencies
下加入"vuepress-plugin-boxx": "0.0.7"
:
1 2 3 "devDependencies": { "vuepress-plugin-boxx": "0.0.7" }
在 vuepress 的config.js
中配置plugins
:
1 2 3 plugins: [ ["vuepress-plugin-boxx" ] ],
在package.json
目录下执行命令:npm install
正常启动项目,接着如下使用即可
使用
引入:只需在你想要插入的地方加入<Boxx/>
即可(如顶部所示)
内容:默认随机展示名人名句,支持自定义
样式:有三种样式,默认为 tip 样式,支持自定义
注意:除<Boxx/>
这个标签是必须外,标签属性均为可选,所有标签属性会在下文中详细介绍
默认样式
自定义标题和内容
如果默认的名人名句不满足需求的话,自定义只需指定两个属性title
和content
的值
Name
Type
Description
title
String
要展示的title
的内容,支持html标签
content
String
要展示的content
的内容,支持html标签
当然你也可以只输入title
或content
,如下:
自定义样式
Name
Type
Description
blockStyle
Object
整体块元素的样式
titleStyle
Object
只针对title
的样式
contentStyle
Object
只针对content
的样式
changeTime
Number
以毫秒值为单位的动态变化时间,顶部为例
需要注意的是:属性值传输的对象只能通过v-bind:
绑定来实现
以下是对如上样式的示例,在Markdown中这样书写即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <marquee> <Boxx :blockStyle="blockStyle" /> <Boxx type="warning" :blockStyle="titleStyle" :titleStyle="titleStyle" changeTime="1000" title="我是一个大大的且变化的 title" /> <Boxx type="danger" :blockStyle="contentStyle" :contentStyle="contentStyle" content="我是一个小小的<br><marquee>content</marquee>" /> </marquee> <script> export default { data() { return { blockStyle: {'background':'#eee','color':'red'}, titleStyle: {'margin-right': '10%','font-size':'16px'}, contentStyle: {'margin-right': '20%','font-size':'10px', "margin-top": "1rem","margin-bottom": "0.4rem"}, } } } </ script>
PWA插件
安装
1 npm install -D @vuepress/plugin-pwa
使用
本选项开启了一个用于刷新内容的弹窗。这个弹窗将会在站点有内容更新时显示出来,并提供了一个 refresh
按钮,允许用户立即刷新内容。
如果没有“刷新”按钮,则只有在所有的 Clients 被关闭后,新的 Service Worker 才会处于活动状态。这意味着用户在关闭你网站的所有标签之前无法看到新内容。但是 refresh
按钮会立即激活新的 Service Worker。
1 2 3 4 5 6 7 ['@vuepress/pwa' , { serviceWorker: true , updatePopup: { message: "发现新内容可用" , buttonText: "刷新" } }],
复制弹窗插件
安装
1 npm install -D vuepress-plugin-nuggets-style-copy
使用
1 2 3 4 5 6 ["vuepress-plugin-nuggets-style-copy" , { copyText: "复制代码" , tip: { content: "复制成功!" } }]
公告弹窗插件
演示
下载
https://www.npmjs.com/package/@vuepress-yard/vuepress-plugin-window
修改源码
不到迫不得已 还是不要修改源码,我主要是因为使用分组的侧边栏后,如果嵌套的内容标题下,不加这个path 参数(如果加了每次点侧边栏标题都会转跳,非常难受),颜色就会偏淡,通过上文中index.styl
无论如何也不能加深
1 2 3 4 5 6 7 8 9 10 children: [ { title: 'Matplotlib' , collapsable: true , children: [ 'Python/Matplotlib/Matplotlib绘图指南' , 'webc/01.Requests使用技巧' , 'webc/02.数据存入Excel' , ]
通过全局搜索,终于找到在源码文件\xxx\blog\node_modules\vuepress-theme-reco\components\SidebarGroup.vue
中发现问题,罪魁祸首就是这个opacity 0.5
,致此,将其改成1即可,虽然简单,但是对于有页面强迫症的我,确实是极大的舒适。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 .sidebar-group background var(--background-color) .sidebar-group padding-left 0.5em &:not(.collapsable) .sidebar-heading :not(.clickable) cursor auto color var(--text-color) &.is-sub-group padding-left 0 & > .sidebar-heading font-size 0.95em line-height 1.4 font-weight normal padding-left 2rem &:not(.clickable) opacity 0.5 & > .sidebar-group-items padding-left 1rem & > li > .sidebar-link font-size : 0.95em ;
参考
znote:https://zpj80231.gitee.io/znote/views/front-end/vuepress-plugin-boxx.html