使用vuepress-theme-reco主题搭建个人博客

经历对多个博客主题的尝试之后,我终于选定了使用vuepress-theme-reco主题(版本2.0.0-rc.16)来搭建我的个人博客,本文主要介绍如何使用vuepress-theme-reco搭建博客。

1. 安装nodejs环境

自行百度nodejs安装,这里不做叙述。

2. 安装主题所需依赖

打开CMD窗口(快捷键:WIN+R):

  • 输入npm install @vuepress-reco/theme-cli@1.0.7 -g 安装脚手架;

  • 输入 theme-cli init 初始化主题:设置目录、博客名称、描述、作者姓名;

  • 进入创建的文件夹目录 cd myblog ,输入npm install vuepress-theme-reco@2.0.0-rc.16安装指定主题依赖到目录下。

以下为安装完成后的目录结构:

image-20240530105506275

3. 启动环境

输入 npm run dev开启环境,浏览器地址栏输入:http://localhost:端口号 访问初始化的博客

image-20240530104357404

可以看到: 端口被占用后会自动切换其他端口,直到成功启动,这时的访问路径为:http://localhost:8083

如果想为博客指定一个端口号,可以在 config.ts中的 export default defineUserConfig({ 添加一句代码:port:9999 ,这样启动时就会以9999 端口启动了,访问路径为:http://localhost:9999

首次访问页面:

image-20240530104735022

4. 将已有内容修改为个人专属

4.1 博客名称和菜单名称

虽然我们在搭建博客时已经输入了博客名称,但是好像最终生成的博客并不生效,所以我们在这里手动修改。

打开文件:.vuepress->config.ts

修改theme: recoTheme中的属性值如:“title”,“description”等,根据自己的实际需要修改navbar(即首页第一行的菜单名称)

如果有自己喜欢的图片也可以修改logo和首页背景图片。背景图片在 README.md 中修改。

4.2 设置菜单栏图标

2.x版本 默认没有给菜单添加图标,下面介绍下怎么自定义菜单图标.

config.ts 文件中,对 navbar 参数进行配置,给某个菜单项添加 icon 属性参数进行图标的配置。vuepress-theme-reco@2.x 是通过 Xiconsopen in new window 来配置图标的,Xicons 只集成了 carbonopen in new window 1 种图标,几乎可以满足绝大部分场景。

navbar: [
      { text: "首页", link: "/", icon: "Home" },

4.3 删除blogs文件夹所有文件

去掉blogs文件夹中所有主题初始化的东西,后面的博客会写在这个文件夹中。

4.4 修改浏览器title图标

config.ts 文件中,添加head 代码,找自己喜欢的图片,然后放到 public 文件夹下:

head: [
    ['link', { rel: 'icon', href: '/favicon.ico' }],
    ['meta', { name: 'keywords', content: '个人博客网页' }],  
    ['meta', { name: 'description', content: '个人博客网页' }],  
    ['meta', { name: 'author', content: 'Mr.Lin' }],   
  ],

4.5 修改主题中的样式

如果要修改主题中某内置页面的样式,那么就要在 .vuepress 目录下创建两个目录:components (存放新建的组件或当与主题的组件同名时覆盖主题对应的组件)/layouts (存放新建的布局或与主题的布局同名时覆盖主题对应的布局)

4.6 修改时间轴页面显示

将主题中的Timeline.vue 复制到.vuepress/layouts 目录下,并修改内容如下:

<template>
  <GenericContainer class="timeline-wrapper">
    <ul class="timeline-content">
      <li
        v-for="(item, index) in timelineData"
        :key="index"
      >
        <h2 class="year">{{item.year}}</h2>
        <ul class="year-wrapper">
          <li v-for="(subItem, subIndex) in item.data" :key="subIndex" class="item">
            <span class="date">{{subItem.date}}</span>

            <RouterLink class="title" :to="subItem.path">{{ subItem.title }}</RouterLink>
          </li>
        </ul>
      </li>
    </ul>
  </GenericContainer>
</template>
<style>
.timeline-wrapper .timeline-content {
    position: relative;
    margin-left: auto;
    margin-right: auto;
    margin-top: 1rem;
    margin-bottom: 4rem;
    max-width: 1024px;
    padding-left: 12rem;
    padding-right: 12rem;
}
/* Hide tooltips on mobile devices */
@media (max-width: 768px) {
  .timeline-wrapper .timeline-content {
    position: relative;
    margin-left: auto;
    margin-right: auto;
    margin-top: 1rem;
    margin-bottom: 4rem;
    max-width: 1024px;
    padding-left: 1rem;
    padding-right: 1rem;
  }
}
@media (max-width: 480px) {
  .timeline-wrapper .timeline-content {
    position: relative;
    margin-left: auto;
    margin-right: auto;
    margin-top: 1rem;
    margin-bottom: 4rem;
    max-width: 1024px;
    padding-left: 1rem;
    padding-right: 1rem;
  }
}

.timeline-wrapper .timeline-content::before {
  content: '';
  position: fixed;
  left: 16rem; /* 调整位置以适应时间线的位置 */
  top: 0;
  bottom: 0;
  width: 10px;
  height: 100%;
  background: #b62c27; /* 箭头的颜色 */
}
/* Hide tooltips on mobile devices */
@media (max-width: 768px) {
  .timeline-wrapper .timeline-content::before {
    content: '';
    position: absolute;
    left: 10rem; /* 调整位置以适应时间线的位置 */
    top: 0;
    bottom: 0;
    width: 0px;
    height: 100%;
    background: #b62c27; /* 箭头的颜色 */
  }
}
@media (max-width: 480px) {
  .timeline-wrapper .timeline-content::before {
    content: '';
    position: absolute;
    left: 10rem; /* 调整位置以适应时间线的位置 */
    top: 0;
    bottom: 0;
    width: 0px;
    height: 100%;
    background: #b62c27; /* 箭头的颜色 */
  }
}

</style>
<script setup lang="ts">
import GenericContainer from '@components/GenericContainer/index.vue'
import { useExtendPageData } from '@vuepress-reco/vuepress-plugin-page/composables'

import { formatISODate } from '@utils/other.js'

const { posts } = useExtendPageData()

const dataMap: {
  [key: string]: Array<any>
} = {}

posts.forEach(post => {
  if (!post.frontmatter.date) return

  let connector = post.frontmatter.date.includes('/') ? '/' : '-'

  const [year, mounth, day] = formatISODate(post.frontmatter.date).split(' ')[0].split(connector) || []

  if (!year || !mounth || !day) return

  if (!dataMap[year]) {
    dataMap[year] = [{
      ...post,
      date: `${mounth}${connector}${day}`
    }]

    return
  }

  dataMap[year].push({
    ...post,
    date: `${mounth}${connector}${day}`
  })
});

interface TimelineData {
  year: string,
  data: any
}

//修改 2024年6月14日10:52:59
// 对每个年份的数据进行倒序排序
Object.keys(dataMap).forEach(year => {
  dataMap[year].sort((a, b) => {
    const dateA = new Date(`${year}-${a.date}`);
    const dateB = new Date(`${year}-${b.date}`);
    return dateB.getTime() - dateA.getTime();
  });
});

// 生成 timelineData 数组,并按年份倒序排序
const timelineData: Array<TimelineData> = Object.keys(dataMap).sort((a, b) => b.localeCompare(a)).reduce(
  (all: Array<TimelineData>, next: string) => {
    all.push({
      year: next,
      data: dataMap[next]
    })
    return all
  },
  []
)
</script>
@client/components/GenericContainer/index.vue

在这个vue 文件中,使列表按照年份倒序显示,并且在列表左边添加了一根轴:以下为页面效果 image-20240716172354540

4.7 添加鼠标点击效果

.vuepress/public/js 目录下创建一个MouseClickEffect.js 文件,内容如下:

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": 99999,
            "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.ts 中的export default defineUserConfig({ 下添加以下代码:

head: [
        ['link', { rel: 'icon', href: '/favicon.ico' }],
        ['meta', { name: 'keywords', content: '个人博客网页' }],  
        ['meta', { name: 'description', content: '个人博客网页' }],  
        //['meta', { name: 'author', content: 'Mr.Lin' }], 
        // 引入jquery
        ["script", {
          "language": "javascript",
          "type": "text/javascript",
          "src": "/js/jquery.min.js"
        }],
        // 引入鼠标点击脚本
        ["script", {
          "language": "javascript",
          "type": "text/javascript",
          "src": "/js/MouseClickEffect.js"
        }] 
]

这样就成功添加了鼠标点击效果: 在博客中鼠标点击时显示 "富强", "民主", "文明", "和谐", "自由", "平等", "公正", "法治", "爱国", "敬业", "诚信", "友善" 的文字。

4.8 分离config.ts中的各配置

如果配置都写在config.ts 中,那么慢慢的这个文件会显得很臃肿,于是我们可以将其中的各种配置单独为一个文件,然后在config.ts 中将其引入即可。那么如何做呢?接着看下去。

以上面的head配置为例,介绍一下操作步骤:

  1. 将对应属性的具体内容单独写为一个文件,这里为.vuepress/public/js/head.ts :

    export default {
        head: [
            ['link', { rel: 'icon', href: '/favicon.ico' }],
            ['meta', { name: 'keywords', content: '个人博客网页' }],  
            ['meta', { name: 'description', content: '个人博客网页' }],  
            //['meta', { name: 'author', content: 'Mr.Lin' }], 
            // 引入jquery
            ["script", {
              "language": "javascript",
              "type": "text/javascript",
              "src": "/js/jquery.min.js"
            }],
            // 引入鼠标点击脚本
            ["script", {
              "language": "javascript",
              "type": "text/javascript",
              "src": "/js/MouseClickEffect.js"
            }] 
        ]
    }
    
  2. config.ts 中引入

    ...
    import headData from './public/js/head';
    export default defineUserConfig({
      ...
      head: headData.head,
    })
    

4.9 配置algolia全文检索

默认的搜索只能根据标题进行检索,这在实际应用中显然很鸡肋,所以必须实现全文检索,我们使用algolia 来实现。在config.ts 中配置如下:

export default defineUserConfig({
  ...
  ...
  theme: recoTheme({
    ...
    ...
    algolia: {
      appId: '*******',
      apiKey: '0dc****************************f06f',
      indexName: 'ide******re',
      inputSelector: '.search-box',
      algoliaOptions: { 'facetFilters': ["lang:$LANG"] },
      debug: false // Set debug to true if you want to inspect the dropdown
    },
    ...
    ...

这样就实现了全文检索:

image-20240716180609790

最近一次更新 3/20/2025, 7:54:12 AM