vuepress-theme-hope主题扩展


vuepress-theme-hope主题

组件的使用

在markdown文件里引入组件(容器)

自定义注册组件

src.vuepress\components\NavCard.vue

<template>
    <el-row :gutter="30">
        <el-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8" v-for="(cardObj, index) in cardArr" :key="index"
            style="margin-top:20px;height:100px;width:100%;overflow:auto;">
            <!-- <el-link class="link-style" :underline="false" target="_blank" :href="cardObj.url" > -->
            <!-- <el-card class="box-card" shadow="always" :body-style="{ padding:'5px' }" > -->
            <el-card shadow="never" :body-style="{ padding: '20px' }">
                <el-row class="box-card-header">
                    <el-col :xs="12" :sm="12" :md="12" :lg="12" :xl="12" style="padding:0px;">
                        <img style="width:30px;height:30px;text-align:left;" :src="$withBase(cardObj.icon)"
                            :alt="cardObj.title" />
                    </el-col>
                    <el-col :xs="12" :sm="12" :md="12" :lg="12" :xl="12" style="padding:0px;">
                        <div style="text-align:right;">
                            <el-tooltip effect="dark" :content="cardObj.desc" placement="bottom">
                                <el-button :type="type" plain
                                    @click.native="gotoSite(cardObj.url)">{{ cardObj.title }}</el-button>
                            </el-tooltip>
                        </div>
                    </el-col>
                </el-row>
                <el-row class="box-card-body">
                    <div style="font-size:10px;color:#999999">{{ cardObj.desc }}</div>
                </el-row>
            </el-card>
            <!-- </el-link> -->
        </el-col>
    </el-row>
</template>


<script>
export default {
    name: "NavCard",
    components: {},
    props: {
        arr: {
            type: String,
            default: ''
        }
    },
    data() {
        return {
            cardArr: JSON.parse(this.arr),
            type: 'success',
        }
    },
    methods: {
        gotoSite(url) {
            // console.log(url);
            // 在新标签页打开
            window.open(url, '_blank').location;
        },
    },
}
</script>


<style>
.link-style {
    width: 100%;
    height: 100%;
    padding: 0px;
}

.box-card {
    width: 100%;
    height: 100%;
}

.box-card-header {
    width: 100%;
    height: 50%;
    margin-bottom: 1px;
    padding: 0px;
}

.box-card-body {
    width: 100%;
    height: 50%;
    margin-top: 1px;
    padding: 0px;
}

.el-card {
    border-radius: 10px;
    border: none;
    background-color: #F6F6F6;
    box-shadow: 0px 1px 5px 4px #0000001a;
}

.el-card:hover {
    transform: scale(1.03); 
    /* boder-top: none; */
    /* background-color: #FDF853; */
    background-color: #98fb98;
}</style>

创建src.vuepress\client.ts

// 客户端增强配置文件-https://v2.vuepress.vuejs.org/zh/guide/migration.html#%E7%BA%A6%E5%AE%9A%E6%96%87%E4%BB%B6%E5%8F%98%E6%9B%B4
import { defineClientConfig } from "@vuepress/client";
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";

export default defineClientConfig({
  enhance: ({ app, router, siteData }) => {
    // 引入Element-plus组件库
    // 【引入的主要目的不是在MD文档中使用Element的组件,主要是为了编写自己的组件】
    // 【自己写的组件被registerComponentsPlugin插件引入全局在进行使用】
    app.use(ElementPlus);
  },
});

在config.ts插件配置中配置

// 注册全局组件的插件
    registerComponentsPlugin({
      componentsDir: path.resolve(__dirname, "./components"),
    }),

同时需要在config.ts头部引入

import { registerComponentsPlugin } from "@vuepress/plugin-register-components";
import { getDirname, path } from "@vuepress/utils";
const __dirname = getDirname(import.meta.url);

这样就可以在src.vuepress\components文件夹下自由引入相应的组件了

例如引入src.vuepress\components\NavCard.vue组件:

---
# # 当前页面内容标题
title: 友链
# 当前页面图标
icon: link
# 分类
category:
  - 友链
# 标签
tag:
  - 博客链接
sticky: false
# 是否收藏在博客主题的文章列表中,当填入数字时,数字越大,排名越靠前。
star: false
# 是否将该文章添加至文章列表中
article: false
# 是否将该文章添加至时间线中
---
## 博客推荐
<NavCard arr='[
{"title":"keney","url":"https://blog.nnxx.me/","desc":"基于hexo-matery搭建的博客","icon":"https://pic.imgdb.cn/item/640d9bf1f144a010073218ac.png"}></NavCard>

效果如下图:

image-20230409171516473

链接

src.vuepress\components\MyLinks.vue

MyLinks.vue

<script setup lang="ts">
import { document } from '../data/document.js';
import { friend } from '../data/friend.js';
import { tools } from '../data/tools.js';

const props = defineProps<{
  type: string;
  src: string;
}>();

let linkData = document;

switch (props.src) {
  case 'document':
    linkData = document;
    break;
  case 'tools':
    linkData = tools;
    break;
  case 'friend':
    linkData = friend;
    break;
  default:
    linkData = document;
}
</script>

<template>
  <div class="MyLinks project-panel" v-if="props.type">
    <template v-if="linkData.length > 0">
      <template v-for="(item, index) in linkData">
        <a
          class="linkWrapper project"
          target="_blank"
          :class="`project${index % 9}`"
          :href="item.href"
          :key="index"
          v-if="item.type.indexOf(props.type) > -1"
        >
          <img class="image" :src="item.cover" />
          <div class="name">
            {{ item.name }}
          </div>
          <div class="desc">
            {{ item.desc }}
          </div>
        </a>
      </template>
    </template>
  </div>
</template>

<style lang="scss" scoped>
a.linkWrapper {
  text-decoration: none;
}
</style>

src.vuepress\data\friend.ts

export const friend = [
  {
    name: 'keney',
    desc: '博客',
    href: 'https://hisnxg.github.io/',
    cover: '/navicon/r2coding.png',
    type: ['friend'],
  },
];

/* 

{
  name: 'xxxx',
  desc: 'xxxx',
  href: 'xxxx',
  cover: 'xxxx',
  type: ['xxx'],
},

 */

ahout.md引入:

---
icon: youlian
---

# 友链

::: tip 欢迎交换友情链接
:::

<MyLinks type="friend" src="friend"/>

---

效果:

image-20230409164014787

参考:https://github.com/mo7cc/BlogSource

自定义链接

src.vuepress\containers\projects.ts

projects.ts:

import yaml from 'js-yaml'
import type Token from 'markdown-it/lib/token.js'
import { withBase } from '../utils'

export interface Project {
  icon: string
  name: string
  desc: string
  link: string
}

/**
 * 渲染容器列表
 * @param tokens
 * @param idx
 * @returns
 */
export const renderProjects = (tokens: Token[], idx: number) => {
  const { nesting: tokenNesting, info: tokenInfo } = tokens[idx]
  // 渲染开头的 ':::' 标记
  if (tokenNesting === 1) {
    let yamlStr = ''
    for (let i = idx; i < tokens.length; i++) {
      const { type, content, info } = tokens[i]
      if (type === 'container_projects_close') break
      if (!content) continue
      if (type === 'fence' && info === 'yaml') {
        // 是代码块类型,并且是yaml代码
        yamlStr = content
      }
    }
    if (yamlStr) {
      const dataObj = yaml.load(yamlStr) // 将yaml字符串解析成js对象
      let dataList: Project[] = []
      if (dataObj) {
        // 正确解析出数据对象
        if (Array.isArray(dataObj)) {
          dataList = dataObj
        } else {
          dataList = dataObj.data
        }
      }
      // 判断是否有数据
      if (dataList && dataList.length) {
        const getProjectItem = (
          project: Project,
          index: number,
          type?: string
        ) => {
          const isFriends = type === 'friends'
          return `
              <a class="project project${index % 9}"
                href="${withBase(project.link)}"
                ${isFriends ? '' : 'rel="noopener noreferrer"'}
                target="_blank">
                <img src="${withBase(project.icon)}"
                  alt="${project.name}" class="image" />
                <div class="name">${project.name}</div>
                <div class="desc">${project.desc}</div>
              </a>
            `
        }
        const getProjects = (projects: Project[], type?: string) => {
          let projectsStr = ''
          projects.map((project, index) => {
            projectsStr += getProjectItem(project, index, type)
          })
          return projectsStr
        }
        const type = tokenInfo.split(' ').pop()
        return `<div class="project-panel">${getProjects(dataList, type)}`
      }
    }
  } else {
    // 渲染':::' 结尾
    return '</div>'
  }
  return ''
}

使用自定义容器需要在packge.json中引入依赖包

"js-yaml": "^4.1.0",

src.vuepress\utils.ts

增加utils.ts

export const withBase = (path: string) => {
  if (!path) return ''
  const base = '/'
  if (base && path.charAt(0) === '/') {
    return base + path.slice(1)
  } else {
    return path
  }
}

src.vuepress\config.ts

在config.ts中插件配置

// VuePress插件配置
// 自定义容器插件
  containerPlugin({
    type: 'projects',
    render: (tokens, idx) => {
      return renderProjects(tokens, idx)
    }
  }),

注意:在config.ts头部引入

>*// VuePress插件配置*

>*// 自定义容器插件*

>import { containerPlugin } from '@vuepress/plugin-container'

>import { renderProjects } from './containers/projects'

通过yaml方式处理,显示会多出代码块,就需要在自定义样式中隐藏掉

src.vuepress\styles\index.scss:

.project-panel {
  a {
    &:hover {
      text-decoration: none;
    }
  }
  .project {
    .image {
      border-radius: 50%;
    }
  }
  .language-yaml {
    display: none;
  }
}

在about.md文件中添加

---
toc: false
breadcrumb: false
---

# 关于本站

一个基于 VuePress 的个人博客。

## 服务提供

本站由以下内容提供服务

::: projects
```yaml

- icon: https://image.liubing.me/2023/02/11/7f17f3cf426c3.png
  name: Cloudflare
  desc: 提供免费的 CDN 服务。
  link: https://www.cloudflare.com/

- icon: https://image.liubing.me/2023/02/11/a6de6381e4ae6.png
  name: Contabo
  desc: VPS 所属供应商。
  link: https://contabo.com/

- icon: https://image.liubing.me/2023/02/11/50994f9710667.ico
  name: 宝塔 Linux 面板
  desc: 用来管理 VPS
  link: https://cn.vuejs.org/

- icon: https://vuepress.vuejs.org/hero.png
  name: VuePress
  desc: 博客驱动引擎。
  link: https://vuepress.vuejs.org/zh/

- icon: https://theme-hope.vuejs.press/logo.png
  name: VuePress Theme Hope
  desc: 本站博客所用主题
  link: https://theme-hope.vuejs.press/zh/

- icon: https://image.liubing.me/2023/02/11/a7643dcbbc234.png
  name: Buddy
  desc: 本站自动化打包构建发布工具。
  link: https://buddy.works

- icon: https://image.liubing.me/2023/02/05/834597e9e927e.png
  name: Waline
  desc: 本站评论所用服务。
  link: https://waline.js.org/
```

:::

效果跟上图一样

功能

评论

在主题插件中配置:

src.vuepress\theme.ts


comment: {
  provider: "Waline",
  serverURL: "自己搭建的walineAPI接口地址",
}

效果:

image-20230409173318195

参考:https://github.com/walinejs/waline

https://plugin-comment2.vuejs.press/zh/

订阅插件

在主题插件中配置:

src.vuepress\theme.ts

//订阅插件SSR
   feed: {
     // 插件选项
     atom: true,
     json: true,
     rss: true,
   },

底部页脚(备案信息)

在src.vuepress\theme.ts配置中

const footer_HTML = `<div class="container-box">
 <div class="footer-btn">
   <a class="footer-icp" href="https://beian.miit.gov.cn" target="_blank">
   <img src="icp.png">
   鄂ICP备2021号
   </a>
   </div>
 </div>`

然后启用页脚即可:

// 全局设置页脚信息
footer: footer_HTML,
// 显示页脚
displayFooter: true,

如果只想局部显示,可以在相应的markdown文件头部添加footer

参考:https://theme-hope.vuejs.press/zh/guide/layout/footer.html

注意

如有报错根据提示,引入相应的依赖,一般在package.json中配置。

附件

参考:

vuepress-theme-hope

vuepress-theme-hope仓库:https://github.com/vuepress-theme-hope/vuepress-theme-hope

https://github.com/mo7cc/BlogSource

https://github.com/liub1934/liubing.me


文章作者: keney
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 keney !
评论
  目录