vuepress-theme-reco是VuePress的一个主题,大家可以参考VuePress和其他主题,搭建你自己风格的主题,这篇主要讲解vuepress-theme-reco主题的博客。
VuePress是静态网页生成器,通过它,可以迅速的将我们的Markdown笔记变成网页,方便我们翻阅,查找。
npm install vuepress-theme-reco --save-dev
theme-cli init blogs
按要求输入内容
将在你的文件夹下生成你项目名的文件夹,我这里是blog.
进到文件夹内,使用cmd执行
npm install
npm run dev
至此博客已经可以正常使用了,但是我们打开官方的案例,往往比我们现在的效果要好,我们需要优化的继续往下看。
像评论、时间线、域名的配置、多语言、暗色适配、侧边栏、文档的摘要…官方写的已经很详细,这里就不再介绍,按照官方文档配置即可。如果有疑问,可以在下面评论,咨询我。
引入依赖:npm i @vuepress-reco/vuepress-plugin-kan-ban-niang
配置
在config.js下的module.exports加入如下代码,可参考npm:
plugins: [
[
'@vuepress-reco/vuepress-plugin-kan-ban-niang',{
theme: [
'miku', 'whiteCat', 'haru1', 'haru2', 'haruto', 'koharu', 'izumi', 'shizuku', 'wanko', 'blackCat', 'z16'
],
clean: false,
messages: {
welcome: '欢迎来到我的博客', home: '心里的花,我想要带你回家。', theme: '好吧,希望你能喜欢我的其他小伙伴。', close: '你不喜欢我了吗?痴痴地望着你。'
},
messageStyle: { right: '68px', bottom: '290px' },
width: 250,
height: 320
}
],
],
效果图
安装依赖:npm i @vuepress-reco/vuepress-plugin-bulletin-popover
修改配置:在config.js下的module.exports的plugin下加入以下代码:
['@vuepress-reco/vuepress-plugin-bulletin-popover', {
title: '公告',
body: [
{
type: 'title',
content: '欢迎加我的QQ/vx ',
style: 'text-aligin: center;',
},
{
type: 'text',
content: 'QQ/VX:1349320519',
style: 'text-align: center;'
},
{
type: 'text',
content: '喜欢的主题特效可以去个人信息',
style: 'text-align: center;'
},
{
type: 'text',
content: '友链或疑问均可在留言板给我留言',
style: 'text-align: center;'
}
],
footer: [
{
type: 'button',
text: '打赏',
link: '/blog/donate'
},
]
}],
],
注意和上一个插件直接有逗号间隔,上述的打赏对应的超链接/blog/donate,你可以在这里定义你自己的打赏页面。
效果图
安装依赖:npm i @vuepress-reco/vuepress-plugin-bgm-player
修改配置:在config.js下的module.exports的plugin下加入以下代码,更多配置参考npm:
[
"@vuepress-reco/vuepress-plugin-bgm-player",{
audios: [
// 本地文件示例
// {
// name: '장가갈 수 있을까',
// artist: '咖啡少年',
// url: '/bgm/1.mp3',
// cover: '/bgm/1.jpg'
// },
// 网络文件示例
{
name: '강남역 4번 출구',
artist: 'Plastic / Fallin` Dild',
url: 'https://assets.smallsunnyfox.com/music/2.mp3',
cover: 'https://assets.smallsunnyfox.com/music/2.jpg'
},
{
name: '用胳膊当枕头',
artist: '최낙타',
url: 'https://assets.smallsunnyfox.com/music/3.mp3',
cover: 'https://assets.smallsunnyfox.com/music/3.jpg'
}
]
}
],
效果图
安装依赖:npm i vuepress-plugin-cursor-effects
修改配置:在config.js下的module.exports的plugin下加入以下代码,更多配置参考npm:
[
"vuepress-plugin-cursor-effects",
{
size: 2, // size of the particle, default: 2
shape: 'circle', // shape of the particle, default: 'star'
zIndex: 999999999 // z-index property of the canvas, default: 999999999
}
],
效果图
修改首页README.md
在根路径下
# 原来的配置内容
# heroImage: /hero.png
# heroImageStyle: {
# maxWidth: '600px',
# width: '100%',
# display: block,
# margin: '9rem auto 2rem',
# background: '#fff',
# borderRadius: '1rem',
# }
bgImageStyle: {
height: '450px'
}
##############################
#修改之后
heroImageStyle: {
maxWidth: '600px',
width: '100%',
display: block,
margin: '9rem auto 2rem',
background: '#fff',
borderRadius: '1rem',
}
bgImage: back1.gif
bgImageStyle: {
height: '1000px'
}
back1.gif文件放在.vuepress下的public下即可,自己找个好看的动图吧。
效果图
安装依赖: npm install vue-canvas-effect --save
修改源码
以前的在node_moudles/vuepress-theme-reco/components/Homeblog.vue,现在的在node_moudles/vuepress-theme-reco/components/HomeBlog/index.vue
在methods方法上加入
mounted (){
import('vue-canvas-effect/src/components/bubbles').then(module => {
this.bubbles=module.default
})
this.recoShow = true
this._setPage(this._getStoragePage())
},
在27行加入
<component v-if="bubbles" :is="bubbles" :options="options">component>
在components所在行下一行加入
data () {
return {
recoShow: false,
currentPage: 1,
tags: [],
bubbles: null
}
},
完整的文件内容如下
<template>
<div class="home-blog">
<div class="hero" :style="{ ...bgImageStyle }">
<div>
<ModuleTransition>
<img
class="hero-img"
v-if="recoShowModule && $frontmatter.heroImage"
:style="heroImageStyle || {}"
:src="$withBase($frontmatter.heroImage)"
alt="hero"
/>
ModuleTransition>
<ModuleTransition delay="0.04">
<h1 v-if="recoShowModule && $frontmatter.heroText !== null">
{{ $frontmatter.heroText || $title || 'vuePress-theme-reco' }}
h1>
ModuleTransition>
<ModuleTransition delay="0.08">
<p v-if="recoShowModule && $frontmatter.tagline !== null" class="description">
{{ $frontmatter.tagline || $description || 'Welcome to your vuePress-theme-reco site' }}
p>
ModuleTransition>
div>
<component v-if="bubbles" :is="bubbles" :options="options">component>
div>
<ModuleTransition delay="0.16">
<div v-show="recoShowModule" class="home-blog-wrapper">
<div class="blog-list">
<note-abstract :data="$recoPosts" @paginationChange="paginationChange" />
div>
<div class="info-wrapper">
<PersonalInfo/>
<h4><reco-icon icon="reco-category" /> {{$recoLocales.category}}h4>
<ul class="category-wrapper">
<li class="category-item" v-for="(item, index) in this.$categories.list" :key="index">
<router-link :to="item.path">
<span class="category-name">{{ item.name }}span>
<span class="post-num" :style="{ 'backgroundColor': getOneColor() }">{{ item.pages.length }}span>
router-link>
li>
ul>
<hr>
<h4 v-if="$tags.list.length !== 0"><reco-icon icon="reco-tag" /> {{$recoLocales.tag}}h4>
<TagList @getCurrentTag="getPagesByTags" />
<h4 v-if="$themeConfig.friendLink && $themeConfig.friendLink.length !== 0"><reco-icon icon="reco-friend" /> {{$recoLocales.friendLink}}h4>
<FriendLink />
div>
div>
ModuleTransition>
<ModuleTransition delay="0.24">
<Content v-show="recoShowModule" class="home-center" custom/>
ModuleTransition>
div>
template>
<script>
import { defineComponent, toRefs, reactive, computed, getCurrentInstance, onMounted } from 'vue-demi'
import TagList from '@theme/components/TagList'
import FriendLink from '@theme/components/FriendLink'
import NoteAbstract from '@theme/components/NoteAbstract'
import { ModuleTransition, RecoIcon } from '@vuepress-reco/core/lib/components'
import PersonalInfo from '@theme/components/PersonalInfo'
import { getOneColor } from '@theme/helpers/other'
export default defineComponent({
components: { NoteAbstract, TagList, FriendLink, ModuleTransition, PersonalInfo, RecoIcon },
data () {
return {
recoShow: false,
currentPage: 1,
tags: [],
bubbles: null
}
},
setup (props, ctx) {
const instance = getCurrentInstance().proxy
const state = reactive({
recoShow: false,
heroHeight: 0
})
const recoShowModule = computed(() => instance && instance.$parent.recoShowModule)
const heroImageStyle = computed(() => instance.$frontmatter.heroImageStyle || {})
const bgImageStyle = computed(() => {
const url = instance.$frontmatter.bgImage
? instance.$withBase(instance.$frontmatter.bgImage)
: require('../../images/bg.svg')
const initBgImageStyle = {
textAlign: 'center',
overflow: 'hidden',
background: `url(${url}) center/cover no-repeat`
}
const { bgImageStyle } = instance.$frontmatter
return bgImageStyle ? { ...initBgImageStyle, ...bgImageStyle } : initBgImageStyle
})
onMounted(() => {
state.heroHeight = document.querySelector('.hero').clientHeight
state.recoShow = true
})
return { recoShowModule, heroImageStyle, bgImageStyle, ...toRefs(state), getOneColor }
},
mounted (){
import('vue-canvas-effect/src/components/bubbles').then(module => {
this.bubbles=module.default
})
this.recoShow = true
this._setPage(this._getStoragePage())
},
methods: {
paginationChange (page) {
setTimeout(() => {
window.scrollTo(0, this.heroHeight)
}, 100)
},
getPagesByTags (tagInfo) {
this.$router.push({ path: tagInfo.path })
}
}
})
script>
<style lang="stylus">
.home-blog {
padding: 0;
margin: 0px auto;
.hero {
margin $navbarHeight auto 0
position relative
box-sizing border-box
padding 0 20px
height 100vh
display flex
align-items center
justify-content center
.hero-img {
max-width: 300px;
margin: 0 auto 1.5rem
}
h1 {
display: block;
margin:0 auto 1.8rem;
font-size: 2.5rem;
}
.description {
margin: 1.8rem auto;
font-size: 1.6rem;
line-height: 1.3;
}
}
.home-blog-wrapper {
display flex
align-items: flex-start;
margin 20px auto 0
padding 0 20px
max-width $homePageWidth
.blog-list {
flex auto
width 0
.abstract-wrapper {
.abstract-item:last-child {
margin-bottom: 0px;
}
}
}
.info-wrapper {
position -webkit-sticky;
position sticky;
top 70px
overflow hidden
transition all .3s
margin-left 15px
flex 0 0 300px
height auto
box-shadow var(--box-shadow)
border-radius $borderRadius
box-sizing border-box
padding 0 15px
background var(--background-color)
&:hover {
box-shadow var(--box-shadow-hover)
}
h4 {
color var(--text-color)
}
.category-wrapper {
list-style none
padding-left 0
.category-item {
margin-bottom .4rem
padding: .4rem .8rem;
transition: all .5s
border-radius $borderRadius
box-shadow var(--box-shadow)
background-color var(--background-color)
&:hover {
transform scale(1.04)
a {
color $accentColor
}
}
a {
display flex
justify-content: space-between
align-items: center
color var(--text-color)
.post-num {
width 1.6rem;
height 1.6rem
text-align center
line-height 1.6rem
border-radius $borderRadius
background #eee
font-size 13px
color #fff
}
}
}
}
}
}
}
@media (max-width: $MQMobile) {
.home-blog {
.hero {
height 450px
img {
max-height: 210px;
margin: 2rem auto 1.2rem;
}
h1 {
margin: 0 auto 1.8rem ;
font-size: 2rem;
}
.description {
font-size: 1.2rem;
}
.action-button {
font-size: 1rem;
padding: 0.6rem 1.2rem;
}
}
.home-blog-wrapper {
display block!important
.blog-list {
width auto
}
.info-wrapper {
// display none!important
margin-left 0
.personal-info-wrapper {
display none
}
}
}
}
}
@media (max-width: $MQMobileNarrow) {
.home-blog {
.hero {
height 450px
img {
max-height: 210px;
margin: 2rem auto 1.2rem;
}
h1 {
margin: 0 auto 1.8rem ;
font-size: 2rem;
}
h1, .description, .action {
// margin: 1.2rem auto;
}
.description {
font-size: 1.2rem;
}
.action-button {
font-size: 1rem;
padding: 0.6rem 1.2rem;
}
}
.home-blog-wrapper {
display block!important
.blog-list {
width auto
}
.info-wrapper {
// display none!important
margin-left 0
.personal-info-wrapper {
display none
}
}
}
}
}
style>
效果图
修改文件
在首页README.md下加入如下代码
<style>
.anchor-down {
display: block;
margin: 12rem auto 0;
bottom: 45px;
width: 20px;
height: 20px;
font-size: 34px;
text-align: center;
animation: bounce-in 5s 3s infinite;
position: absolute;
left: 50%;
bottom: 30%;
margin-left: -10px;
cursor: pointer;
}
@-webkit-keyframes bounce-in{
0%{transform:translateY(0)}
20%{transform:translateY(0)}
50%{transform:translateY(-20px)}
80%{transform:translateY(0)}
to{transform:translateY(0)}
}
.anchor-down::before {
content: "";
width: 20px;
height: 20px;
display: block;
border-right: 3px solid #fff;
border-top: 3px solid #fff;
transform: rotate(135deg);
position: absolute;
bottom: 10px;
}
.anchor-down::after {
content: "";
width: 20px;
height: 20px;
display: block;
border-right: 3px solid #fff;
border-top: 3px solid #fff;
transform: rotate(135deg);
}
</style>
<script>
export default {
mounted () {
const ifJanchor = document.getElementById("JanchorDown");
ifJanchor && ifJanchor.parentNode.removeChild(ifJanchor);
let a = document.createElement('a');
a.id = 'JanchorDown';
a.className = 'anchor-down';
document.getElementsByClassName('hero')[0].append(a);
let targetA = document.getElementById("JanchorDown");
targetA.addEventListener('click', e => { // 添加点击事件
this.scrollFn();
})
},
methods: {
scrollFn() {
const windowH = document.getElementsByClassName('hero')[0].clientHeight; // 获取窗口高度
document.documentElement.scrollTop = windowH; // 滚动条滚动到指定位置
}
}
}
</script>
效果图
安装依赖:npm i vuepress-plugin-ribbon-animation
修改config.js下的plugins,可参考npm
["ribbon-animation", {
size: 90, // 默认数据
opacity: 0.3, // 透明度
zIndex: -1, // 层级
opt: {
// 色带HSL饱和度
colorSaturation: "80%",
// 色带HSL亮度量
colorBrightness: "60%",
// 带状颜色不透明度
colorAlpha: 0.65,
// 在HSL颜色空间中循环显示颜色的速度有多快
colorCycleSpeed: 6,
// 从哪一侧开始Y轴 (top|min, middle|center, bottom|max, random)
verticalPosition: "center",
// 到达屏幕另一侧的速度有多快
horizontalSpeed: 200,
// 在任何给定时间,屏幕上会保留多少条带
ribbonCount: 2,
// 添加笔划以及色带填充颜色
strokeSize: 0,
// 通过页面滚动上的因子垂直移动色带
parallaxAmount: -0.5,
// 随着时间的推移,为每个功能区添加动画效果
animateSections: true
},
ribbonShow: false, // 点击彩带 true显示 false为不显示
ribbonAnimationShow: true // 滑动彩带
}]
效果图
修改文件
在首页README.md下的style里设置body的背景图片,完成第8条的向下跳转,写入的style。
body{
background-image: url(背景图的url);
}
背景图
如果你在搭建过程中遇到问题,就在下方留言联系我或者访问我的博客获取我的联系方式。也可以在在线聊天室大家一块交流。