banner
keney

keney

remain optimistic
twitter

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://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

Github Repo not found

The embedded github repo could not be found…

Github Repo not found

The embedded github repo could not be found…

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.