个人知识库

lishihuan大约 19 分钟

个人知识库

Obsidian

参考open in new window

使用vuepress-theme-hope 搭建 文档系统作为 个人知识库

部署脚本: https://lovelijunyi.gitee.io/posts/169.htmlopen in new window

安装:https://bornforthis.cn/1v1/18-Jason/03.htmlopen in new window

官网:https://theme-hope.vuejs.press/zh/open in new window

https://zhuanlan.zhihu.com/p/494269087open in new window

https://blog.csdn.net/weixin_43711004/article/details/126962196open in new window

https://www.cnblogs.com/shaozelong/p/16988680.htmlopen in new window

部署上线: https://blog.csdn.net/goodProgramer/article/details/112345149open in new window

博客源码:

https://github.com/Mister-Hope/Mister-Hope.github.ioopen in new window

https://gitee.com/xt-gitee/mynotesopen in new window

安装

npm init vuepress-theme-hope@next my-docs
npm init vuepress-theme-hope my-docs

项目命令

package.json

{
  "scripts": {
    "docs:build": "vuepress build src",
    "docs:clean-dev": "vuepress dev src --clean-cache",
    "docs:dev": "vuepress dev src"
  }
}

启动命令

npm run docs:dev

使用组件

全局导入 Vue 组件

根据组件文件或目录自动注册 Vue 组件。

npm i -D @vuepress/plugin-register-components@next

"@vuepress/client": "2.0.0-beta.53",
"@vuepress/plugin-register-components": "^2.0.0-beta.51",
"@vuepress/plugin-search": "^2.0.0-beta.53",
"element-plus": "^2.2.25",
"vue": "^3.2.45",
"vuepress": "2.0.0-beta.53",
"vuepress-theme-hope": "2.0.0-beta.130"
plugin-search 这个插件只能实现文章查找,最后的显示结果由文章列表组成,不能实现全文搜索。
npx vuepress info
useRouteLocale() is called without provider.
img
img
yarn add -D @vuepress/plugin-search
yarn add -D @vuepress/@sass-palette/hope-config

全文搜索

1. vuepress-plugin-search-pro 搜索

通过 vuepress-plugin-search-pro 设置 indexContent: true 实现全文搜索

npm i -D vuepress-plugin-search-pro
// .vuepress/config.ts
import { searchProPlugin } from "vuepress-plugin-search-pro";

export default {
  plugins: [
    searchProPlugin({
      // 配置选项
         indexContent: true, // 默认情况下,插件只会索引页面的标题和摘要以及你的自定义索引项,不会索引页面的正文内容。如果需要索引页面的正文内容,可以将该选项设置为 true。
    }),
  ],
};

2. Algolia DocSearch 搜索

申请网站open in new window

其他

使用:

VuePress 2.0 中使用 Algolia DocSearch 文档搜索功能的配置 | ImCaO's Blogopen in new window

搜索

Vuepress配置全文搜索插件fulltext-sarch | 二丫讲梵 (eryajf.net)open in new window

http://www.manongjc.com/detail/62-lbqpntwnmfrkbsx.htmlopen in new window

https://zhuanlan.zhihu.com/p/369923082open in new window

https://blog.sofineday.com/vuepress-fulltext-search.html#通过插件-vuepress-plugin-fulltext-search-实现全文搜索open in new window

https://www.cnblogs.com/pengchenggang/p/15713929.htmlopen in new window

https://blog.csdn.net/weixin_55475226/article/details/123363042open in new window

https://blog.sofineday.com/vuepress-fulltext-search.html#集成第三方免费搜索服务-algoliaopen in new window

其他

https://songjun520.cn/open in new window

出现跨域异常

使用 gitee pages 部署 出现跨域异常

src/.vuepress/config.ts 文件中修改

// /notes_book_docs/是博客的根目录,同样也得是gitee仓库的名字
"base": "/notes_book_docs/"

使用记录

图标库设置

本地iconfont文件位置.vuepress/public/iconfont/iconfont.css

// iconAssets: '/iconfont/iconfont.css', 可以指定本地iconfont文件
iconAssets: ['/iconfont/iconfont.css','//at.alicdn.com/t/c/font_4063270_fk8t8tiuwa.css'],
iconPrefix:'iconfont ', // 设置的图标前缀 这里指定,否则在使用时就需要  iconfont icon-<ICON-NAME>

在 Markdown 中添加图标

你可以使用 <HopeIcon /> 组件在 markdown 中添加图标。

  • icon 属性接受与其他 icon 选项相同的内容,即:字体类名和图像 url
  • color 属性接受一个 css 颜色值,它将用作图标颜色(可选)
  • size 属性接受一个 css 大小值,该值将用作图标大小(可选)

例如:

.vuepress/theme.ts

plugins: {
    copyright: {                 // 开启复制文章,加入版权信息
        author: "lihuan",       // 作者
        license: "", // 许可证
        triggerLength: 50,         // 触发附加版权的最小内容长度
        global: true,              // 开启全局,允许在页面的 frontmatter 中单独设置 copy: false 禁用
    },
}

菜单

  • navbar:导航栏
  • sidebar:侧边栏

左侧菜单,显示的名称,是md的一级标题(所以需要保证只有一个一级标题,否则可能路由跳转会异常)

目前菜单分为3中类型

以文档内容为侧边栏目录

    {
      text: "文档",
      icon: "note",
      prefix: "guide/",
      children: "structure",
    },

分组

"/notes/java/java/": [
    "java基础",// "/notes/java/java/java基础.md"
    "java开发记录",
  ],
 "/notes/java/": [
    {
      // 必要的,分组的标题文字
      text: "java基础",
      icon: "icon-java1",
      prefix: "java/",
      // 可选的, 设置分组是否可以折叠,默认值是 false,
      collapsible: true,
      // 必要的,分组的子项目
      children: [
         "",
        "java基础",
        "java开发记录","github", "Hibernate-Validator数据校验框架", "JAVA_IO", "java开发记录", "java环境安装", "maven", "Netty", "springBoot", "springCloud"
      ],
    },
    {
      // 必要的,分组的标题文字
      text: "Activiti",
      icon: "icon-liucheng",
      prefix: "Activiti/",
      // 可选的, 设置分组是否可以折叠,默认值是 false,
      collapsible: true,
      // 必要的,分组的子项目
      children: [
        "Activiti", "Activiti_6", "Activiti数据库设计", "Activiti_使用"
      ],
    },
  ],

拓展记录

1. 使用element-plus 组件

就目前了解的方式,应该是有2种使用方式(chatGPT 给出的答案)

  1. 组件的组件使用
  2. 在 Markdown 页面中使用 Element Plus 的组件

第一种实现:编写自己的组件时使用 Element Plus(目前确认能实现)

1.安装element
npm install element-plus --save-dev
2. 在 .vuepress文件夹下添加 client.ts文件
// .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);
  },
});

第二种实现

目前没验证过

  1. 安装 Element Plus

    在终端中进入您的 VuePress 项目目录,并执行以下命令来安装 Element Plus 包:

    install element-plus --save-dev
    

    这将会在您的项目中添加 Element Plus 的依赖。

  2. 在主题中引入 Element Plus 样式和组件

    您可以在 .vuepress/theme/index.js 文件中引入 Element Plus 的样式文件和组件。例如,您可以按照以下方式进行配置:

    module.exports = {
      async ready() {
        const { setVuePressThemeDefaultConfig } = require('vuepress-theme-hope/src/node')
        // 引入 Element Plus 的样式文件
        require('element-plus/lib/theme-chalk/index.css')
    
        // 引入 Element Plus 的组件
        const ElButton = require('element-plus/lib/button').default
    
        setVuePressThemeDefaultConfig({
          plugins: [
            // 注册 Element Plus 插件
            [
              'element-plus',
              {
                components: {
                  ElButton,
                },
              },
            ],
          ],
        })
      },
    }
    

    在上述代码中,我们使用 require 函数引入了 Element Plus 的 CSS 样式文件和 ElButton 组件。然后,我们在 plugins 配置项中注册了 Element Plus 的插件,并在其中指定了要注册的组件。这样,VuePress 就会将 Element Plus 转换为可用的组件。

  3. 在页面中使用 Element Plus 组件

    现在,您可以在您的 VuePress 页面中使用 Element Plus 的组件了。例如,在 Markdown 页面中使用 ElButton 组件的示例代码如下:

    <template>
      <div>
        <el-button type="primary">默认按钮</el-button>
      </div>
    </template>
    

    在上述示例中,我们使用 type 属性来指定按钮类型为 primary,这将使该按钮显示为蓝色。

2. 全局挂载/使用

下面以 LeanCloud数据库为例:

.vuepress/client.ts 目录下

// .vuepress/client.ts
import { defineClientConfig } from "@vuepress/client";
import { ui_rmd_menu } from './public/data/commonMenuData'



export default defineClientConfig({
  enhance: ({ app }) => {
      app.config.globalProperties.$ui_rmd_menu = ui_rmd_menu;// 挂载 ui_rmd_menu 对象
    
  },
});

使用

可以直接在md中使用下面的代码

<script setup lang="ts">
    import { getCurrentInstance   } from "vue";
    const { proxy }: any = getCurrentInstance()
    console.log('proxy:', proxy)
    console.log('$ui_rmd_menu:', proxy.$ui_rmd_menu);// 调用 挂载的全局变量

</script>

3. 使用vuex和 路由

以项目中 记录常用菜单为例

3.1 安装

npm i vuex vue-router -S

3.2 添加.vuepress/router.js 文件

在 router.js 文件中,你设置了路由守卫以更新页面点击次数,并将其存储在 Vuex Store 中。

export default ({ router, store }) => {
    // 路由守卫:更新页面点击次数
    router.beforeEach((to, from, next) => {
        console.log(to)
        console.log(store.getters.popularPages);
        store.commit('SET_PAGE_COUNT', to.path);
        next();
    });
};

3.3 添加.vuepress/store.js 文件

在 store.js 文件中,你定义了一个 popularPages Getter,它通过过滤、排序和筛选来计算出常用页面的列表,并将其存储在状态管理中

import Vuex from 'vuex'
export default new Vuex.Store({
    state: {
        pageCountMap: (typeof window !== 'undefined') ? JSON.parse(window.localStorage.getItem('pageCountMap')) || {} : {}
    },
    mutations: {
        SET_PAGE_COUNT (state, pathItem) {
            const key = pathItem.path
            if (state.pageCountMap[key]) {// 说明当前path 已经缓存过,点击次数+1
                state.pageCountMap[key].count++
            } else {
                state.pageCountMap[key] = {
                    path: pathItem.path,
                    name: pathItem.meta.t,
                    count: 1
                }
            }
            if (typeof window !== 'undefined') {
                window.localStorage.setItem('pageCountMap', JSON.stringify(state.pageCountMap))
            }
            // state.pageCountMap[path] = (state.pageCountMap[path] || 0) + 1;
        },
    },
    getters: {
        popularPages (state) {
            // let pageCountMap = {};
            // if (typeof window !== 'undefined') {
            //     pageCountMap = JSON.parse(localStorage.getItem('pageCountMap')) || {}
            // }else{
            //     pageCountMap = state.pageCountMap
            // }
            const pageList = Object.entries(state.pageCountMap) // 将对象转换为键值对数组
            const arr = pageList
                .filter(([path,  count]) => path !== '/') // 过滤掉首页和 name 为空的项
                .sort((a, b) => b[1].count - a[1].count) // 按照点击次数倒序排序
                .slice(0, 20) // 只取前20个
            const menuArr = arr.map(([_, item]) => item)
                .filter(({name}) => !!name);
            return menuArr;
        },
    },
})

2.4 在 client.ts 文件中,你使用 routerMixin 函数将路由守卫和状态管理绑定到 VuePress 应用程序中。

添加.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";
import store from './store';
import routerMixin from './router';

export default defineClientConfig({
  enhance: ({ app, router, siteData }) => {
    // 引入Element-plus组件库
    // 【引入的主要目的不是在MD文档中使用Element的组件,主要是为了编写自己的组件】
    // 【自己写的组件被registerComponentsPlugin插件引入全局在进行使用】
    app.use(ElementPlus).use(store);
      // 传入 router 和 store 对象,执行路由守卫代码
      app.config.globalProperties.$store = store; // 挂载 store
      routerMixin({ router:router, store }); // 执行路由守卫
  },
});

自定义组件支持scss

<style scoped lang="scss">

4. 自定义组件使用

以首页使用快速导航栏为例,卡片是自定义组件,并且将数据提取作为公共js对象,通过导入全局变量使用(变量的使用,目前总共2种方式)

  • 通过vuex 共享全局变量
  • 直接引入

案例:首页计划是存放一些常用的导航推荐,并且加上常用菜单

image-20230609231438672
image-20230609231438672

实现步骤:

1. 自定义组件

https://vuejs.press/zh/reference/plugin/register-components.htmlopen in new window

https://theme-hope.vuejs.press/zh/cookbook/customize/component.htmlopen in new window

// src/.vuepress/config.ts 
import {defineUserConfig} from "vuepress";
import theme from "./theme.js";
import { registerComponentsPlugin } from '@vuepress/plugin-register-components'
import { getDirname, path } from '@vuepress/utils'
// @ts-ignore
const __dirname = getDirname(import.meta.url)
export default defineUserConfig({
    plugins: [
        registerComponentsPlugin({
            // components: {
            //     FooBar: path.resolve(__dirname, './components/FooBar.vue'), // 用于替换
            // },
            componentsDir: path.resolve(__dirname, './components');// 指定 src/.vuepress/components
        })
    ],
});

componentsDir

2. 编写导航组件

NavCard.vue

QuickAccessCard.vue

3. 定义变量

将导航菜单提出放到一个js对象中全局维护,这样数据会纯粹一点

src/.vuepress/public/data/commonMenuData.ts

/**
 *  目前快速导航对象总共有五个属性
 *      1. img:网站图标(可无)
 *      2. name:网站名称(必填,在没有 img和iconFont 属性时,用 name的第一个字符作为 网站的图标)
 *      3. description:网站说明(必填)
 *      4. url:网站url地址(必填)
 *      5. tag:卡片右上角 标签,主要用于描述 该网站 为 官网,防止 相同的网站很多,需要哦区分开
 *      6. iconFont 计划作为 替代 img的,
 *
 */
// UI 框架 罗列的导航网站  https://c.runoob.com/web-developer/
export const ui_rmd_menu = [
    {
        img: '/images/home/Bootstrap-icon.jpg',
        name: 'Bootstrap',
        description: '最受欢迎的 HTML、CSS 和 JS 框架,用于开发响应式布局、移动设备优先的 WEB 项目',
        'url': 'http://v3.bootcss.com/'
    },
    { img: '/images/home/Ant.Design.png', name: 'Ant Design', description: '一个服务于企业级产品的设计体系,基于『确定』和『自然』的设计价值观,通过模块化的解决方案,让设计者专注于更好的用户体验','url': 'https://ant.design/index-cn' },
    {

        img: '/images/home/element.jpg',
        name: 'Element',
        description: '一个服务于企业级产品的设计体系,基于『确定』和『自然』的设计价值观,通过模块化的解决方案,让设计者专注于更好的用户体验',
        url: 'http://element-cn.eleme.io/#/zh-CN'
    },
    {

        img: '/images/home/layui.jpg',
        name: 'layui',
        description: 'Layui 是一款采用自身模块规范编写的情怀型前端UI框架,遵循原生HTML/CSS/JS的书写与组织形式,门槛极低,拿来即用',
        url: 'http://www.layui.com/'
    }
]

4. 全局变量的使用

4.1 在 client.ts 文件中 将 上面定义的变量 挂载全局
// .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";
import store from './store/store';
import routerMixin from './router/router';
import { ui_rmd_menu , chartLibrary,web_study,java_study,tool_rmd_menu,api_tool ,css_tool, other_rmd_menu } from './public/data/commonMenuData'
export default defineClientConfig({
  enhance: ({ app, router, siteData }) => {
    // 引入Element-plus组件库
    // 【引入的主要目的不是在MD文档中使用Element的组件,主要是为了编写自己的组件】
    // 【自己写的组件被registerComponentsPlugin插件引入全局在进行使用】
    app.use(ElementPlus).use(store);
      // 传入 router 和 store 对象,执行路由守卫代码
      app.config.globalProperties.$store = store; // 挂载 store
      app.config.globalProperties.$router = router; // 挂载 router
      app.config.globalProperties.$rmd_menu = {...{'ui':ui_rmd_menu},...{'chartLibrary':chartLibrary},...{'web_study':web_study},...{'java_study':java_study},...{'tool':tool_rmd_menu},...{'css_tool':css_tool},...{'api_tool':api_tool},...{'other':other_rmd_menu}};
      routerMixin({ router:router, store }); // 执行路由守卫
  },
});
4.2 通过引入变量,使用全局变量

指定@NavCardMenuData 对应 "./public/data/commonMenuData.ts" 下的js 文件

// .vuepress/config.ts

    alias: {
        "@theme-hope/modules/blog/components/BlogHero": path.resolve( __dirname, "./components/BlogHero.vue"),/*替换 博客首页*/
       '@theme-hope/components/NormalPage': path.resolve(__dirname, './components/NormalPage.vue'),
       "@NavCardMenuData": path.resolve(__dirname, "./public/data/commonMenuData.ts"),  // 博客首页,推荐菜单
    }

在需要的md文件中

<NavCard title="UI 框架" icon="icon-uicn" :cards="ui_rmd_menu" />

<script setup lang="ts">
import {ui_rmd_menu} from "@NavCardMenuData";
</script>

4.5. 调用


<QuickAccessCard />

<NavCard title="UI 框架" icon="icon-uicn" :cards="$rmd_menu.ui" />

云数据库的使用

LeanCloudopen in new window

1. 初始化LeanCloud数据库

// .vuepress/client.ts
import { defineClientConfig } from "@vuepress/client";

import AV from 'leancloud-storage';
// 初始化 LeanCloud SDK
AV.init({
    appId: '47ldhKIDeDK2V3Ae4tnj9qIk-gzGzoHsz',
    appKey: 'sXOILFKBZZvKWMfQHRiCABNA',
    serverURL: "https://47ldhkid.lc-cn-n1-shared.com",
})


export default defineClientConfig({
  enhance: ({ app }) => {
      app.config.globalProperties.$av = AV; // 挂载AV (LeanCloud 云数据库)
  },
});

考虑到后期需要对数据进行一些操作,所以讲涉及到 LeanCloud 的部分封装出去

2 封装 LeanCloud 相关数据库操作(=============================待完善)

创建.vuepress/utils/leancloud.ts

import AV from 'leancloud-storage';
// https://console.leancloud.cn/apps
// 初始化 LeanCloud SDK
AV.init({
    appId: '47ldhKIDeDK2V3Ae4tnj9qIk-gzGzoHsz',
    appKey: 'sXOILFKBZZvKWMfQHRiCABNA',
    serverURL: "https://47ldhkid.lc-cn-n1-shared.com",
})

// 数据插入方法
export function insertData(data: any) {
    // 这里是数据插入逻辑,您可以根据需求进行具体实现
    // 示例代码:假设您的数据模型是 TestObject
    const TestObject = AV.Object.extend('TestObject');
    const testObject = new TestObject();
    return testObject.save(data);
}

// 数据查询方法
export function queryData(objectId: any) {
    const commonMenuQuery = new AV.Query("common_menu");
    commonMenuQuery.get(objectId).then((commonMenu) => {
        const type = commonMenu.get("type");
        const content = commonMenu.get("content");
        console.log(type)
        console.log(JSON.parse(content));
        console.log(commonMenu)
    });
}

export default AV;

3. 挂载全局

// .vuepress/client.ts
import { defineClientConfig } from "@vuepress/client";
import AV from './utils/leancloud' //初始化 LeanCloud 数据库

export default defineClientConfig({
  enhance: ({ app }) => {
      app.config.globalProperties.$av = AV; // 挂载AV (LeanCloud 云数据库)
  },
});

全局导入 Vue 组件

https://theme-hope.vuejs.press/zh/cookbook/customize/component.htmopen in new window

目前自定义的组件都放到 .vuepress/components 目录下

目前知道的有3种方式:(前两种都是在 .vuepress/config.ts 中实现)

  • 通过 @vuepress/plugin-register-components 注册组件
  • alias 中通过别名的方式
  • 通过 ClientConfigFile 注册 (在 .vuepress/client.ts 中实现)

第一种方式/第二种方式

// .vuepress/config.ts
import {defineUserConfig} from "vuepress";
import { getDirname, path } from '@vuepress/utils';
import { registerComponentsPlugin } from '@vuepress/plugin-register-components'
export default defineUserConfig({
    // 其他参数
    plugins: [
        registerComponentsPlugin({
            // 下面这个目前还不确定,是用于替换默认主题,还是 全局导入 Vue 组件
            // components: {
            //     FooBar: path.resolve(__dirname, './components/FooBar.vue'), // 用于替换 单个
            // },
            // 第一种方式: 在这里指定
            // 这步核心:在 .vuepress/components 中定义的vue组件要想全局使用,需要在registerComponentsPlugin 指定
            componentsDir: path.resolve(__dirname, './components')
        })
    ],
    alias: {
        // 方式二: 通过指定别名,这样需要在使用的 文件中 通过   import {NavCard} from "@NavCard"  引入
        "@NavCard": path.resolve(__dirname, "./components/NavCard.vue"),            //自定义卡片组件
    }
});

说明

方式一:通过下面的方式,将整个 .vuepress/components 中的组件全局导入,md文件中就能直接使用

registerComponentsPlugin({
            componentsDir: path.resolve(__dirname, './components')
 })

方式二:通过指定别名,这样需要在使用的 文件中 通过 import {NavCard} from "@NavCard" 引入

 alias: {
        "@NavCard": path.resolve(__dirname, "./components/NavCard.vue"),            //自定义卡片组件
    }

方式三

你可以通过创建 .vuepress/client.ts 手动注册组件。 ====================没验证过

// .vuepress/client.ts
import { defineClientConfig } from "@vuepress/client";
import NavCard from "./NavCard.vue";

export default defineClientConfig({
  enhance: ({ app, router, siteData }) => {
    app.component("NavCard", NavCard);
  },
});

使用本地文件

场景: 目前首页导航菜单推荐,考虑到数据多,所以单独使用js文件存储

目前文件存储位置 ./public/data/commonMenuData.ts

目前2种方式拿到本地的js数据文件

  • 将数据全局挂载,

  • 通过 alias 创建文件的别名,后面就可直接使用(因为无法使用相对路径进行导入,所以通过别名的方式)

第一种方式:

// .vuepress/config.ts
import {defineUserConfig} from "vuepress";
import { getDirname, path } from '@vuepress/utils';
import { registerComponentsPlugin } from '@vuepress/plugin-register-components'
export default defineUserConfig({
    // 其他参数
    plugins: [
        registerComponentsPlugin({
            // 这步核心:在 .vuepress/components 中定义的vue组件要想全局使用,需要在registerComponentsPlugin 指定
            componentsDir: path.resolve(__dirname, './components')
        })
    ],
    alias: {
        // 博客首页,推荐菜单(这里通过别名定义了该js文件,后面其他页面中就可以直接使用  import {ui_rmd_menu} from "@NavCardMenuData";)
        "@NavCardMenuData": path.resolve(__dirname, "./public/data/commonMenuData.ts"),               
    }
});

使用: (需要额外说明的是:可以在Markdown 中使用 Vue 语法

//xx.md 
<NavCard title="UI 框架" icon="icon-uicn" :cards="ui_rmd_menu" />
<script setup lang="ts">
import {ui_rmd_menu} from "@NavCardMenuData";
</script>

第二种:挂载全局使用

.vuepress/client.ts 目录下

// .vuepress/client.ts
import { defineClientConfig } from "@vuepress/client";
import { ui_rmd_menu } from './public/data/commonMenuData'



export default defineClientConfig({
  enhance: ({ app }) => {
      app.config.globalProperties.$ui_rmd_menu = ui_rmd_menu;// 挂载 ui_rmd_menu 对象
  },
});

使用: 直接在 md文件中即可使用,NavCard组件的处理和上面的一样

//xx.md 
<NavCard title="UI 框架" icon="icon-uicn" :cards="ui_rmd_menu" />

替换组件

https://theme-hope.vuejs.press/zh/guide/advanced/replace.htmlopen in new window

源码open in new window

当在 行为选项open in new window 中设置 { custom: true } 时,主题将通过 @theme-hope 别名来引入组件,所以你可以利用这一点来替换主题的任何一个组件。

.vuepress/theme.ts 中设置 { custom: true }

image-20231109233114305
image-20231109233114305

通过 alias 替换主题中使用的组件别名

// .vuepress/config.ts
import { getDirname, path } from "@vuepress/utils";
import { defineUserConfig } from "vuepress";
import { hopeTheme } from "vuepress-theme-hope";
import theme from "./theme.js";

const __dirname = getDirname(import.meta.url);

export default defineUserConfig({
 theme,
  alias: {
      // 目的是利用 tocBefore navbarEndBefore 这 2个插槽 添加自定义的天气组件
    '@theme-hope/components/NormalPage': path.resolve(__dirname, './components/NormalPage.vue'), 
    ),
  },
});

天气

结合上面的 替换组件, 通过 NormalPage.vue 替换原来的组件,在tocBefore 插槽中添加 天气组件

<!-- components/NormalPage.vue -->
<template>
    <NormalPage>
        <template v-slot:tocBefore>
            <WeatherPopup/>
        </template>
        <template v-slot:navbarEndBefore>
            <WeatherPopup/>
        </template>
        <slot/>
    </NormalPage>
</template>


<script setup lang="ts">
    import NormalPage from 'vuepress-theme-hope/components/NormalPage'
    import WeatherPopup from './WeatherPopup.vue'
</script>

WeatherPopup.vue

<template>
    <div @click.stop="showWeatherPopup">
        <iframe id="iframe" scrolling="no" :src="'https://tianqiapi.com/api.php?style=ty&skin=cucumber&city='+city" frameborder="0"
                width="300" height="75" allowtransparency="true"></iframe>
        <!-- <iframe width="320" height="85" frameborder="0" scrolling="no" hspace="0" src="https://i.tianqi.com/?c=code&a=getcode&id=6&py=chongqing&icon=1"></iframe> -->

        <el-dialog v-model="dialogVisible" title="" width="30%" >
            <iframe scrolling="no" :src="'https://tianqiapi.com/api.php?style=tw&skin=pitaya&city='+city" frameborder="0" width="100%"
                    height="300px" allowtransparency="true"></iframe>
        </el-dialog>

    </div>

</template>

<script>
    import axios from 'axios'

    export default {
        data() {
            return {
                weather: {},
                city: '合肥',
                dialogVisible:false
            }
        },
        mounted() {
            // 构造 API 请求 URL
            var ipUrl = "https://restapi.amap.com/v3/ip?key=bcc1d8e1b72de9bd3e9ed2561ac10a2b";

            // 向 API 发送 HTTP 请求
            axios.get(ipUrl)
                .then(({data}) => {
                    // 获取 IP 地址对应的城市名称
                    var city = data.city;
                    this.city = city.replace(/市$/, '');
                })
                .catch(error => {
                    console.error(error);
                });

        },
        created() {

        },
        methods: {
            showWeatherPopup() {
                this.dialogVisible = true;
            }
        },
    }
</script>

<style scoped>
    #iframe {
        pointer-events: none;
    }
</style>

博客首页使用自定义组件

参考:https://theme-hope.vuejs.press/zh/guide/advanced/presets.htmlopen in new window

目前主要是2快

  • 将博客主页的背景替换为每日的必应壁纸。
  • 将博客主页的描述替换为随机的一言词句。

为了通过别名替换组件,需要将 { custom: true } 作为第二个选项传入 hopeTheme

.vuepress/theme.ts

export default hopeTheme({
    hostname: "http://mylishihuan.gitee.io",
    author: {
        name: "lishihuan",
        url: "http://mylishihuan.gitee.io/notes_book_docs/",
    },
    // iconAssets: "iconfont",
    // 静态资源访问,不需要加 public
    iconAssets: '/iconfont/iconfont.css',
},{ custom: true });    

必应壁纸

bgImage: https://file.mo7.cc/api/public/bzopen in new window 目前不知道这个接口的由来,但是他可以获取随机获取必应图纸,可以不用下面的 自定义组件方式

---
home: true
layout: BlogHome
hero: true
bgImage: /blogImage/blog_background2.jpg
bgImage: https://file.mo7.cc/api/public/bz
heroImage: /avatar/head_photo.png
heroText: lihuaun个人笔记
heroFullScreen: true
projects:
  - name: Maven仓库
    link: https://mvnrepository.com/	
    desc: Jar包的搜索及下载地址
    icon: link
  - name: B站
    link: https://www.bilibili.com/	
    desc: B站
    icon: link
---

自定义组件使用必应壁纸

// .vuepress/config.ts
import { getDirname, path } from "@vuepress/utils";
import { defineUserConfig } from "vuepress";

const __dirname = getDirname(import.meta.url);

export default defineUserConfig({
  // ...

  alias: {
      // 通过自定义的BlogHero.vue 组件替换掉原来的博客首页组件
    "@theme-hope/modules/blog/components/BlogHero": path.resolve(
      __dirname,
      "./components/BlogHero.vue"
    ),
  },
});

在components文件夹下添加BlogHero.vue 覆盖原组件

<!-- .vuepress/components/BlogHero.vue -->
<script setup lang="ts">
import BlogHero from "vuepress-theme-hope/blog/components/BlogHero.js";
import BingHeroBackground from "vuepress-theme-hope/presets/BingHeroBackground.js";
</script>

<template>
  <BlogHero>
    <template #heroBg>
      <BingHeroBackground />
    </template>
  </BlogHero>
</template>

一言描述

来自 theme-hope 主题文档 一言描述open in new window

和必应壁纸一样,店铺是替换BlogHero组件

  • 博客主页的描述替换为随机的一言词句。
  • 一言名句组件"vuepress-theme-hope/presets/HitokotoBlogHero.js"
  • 使用方法:覆盖 @theme-hope/modules/blog/components/BlogHero,将上方组件导入原 BlogHero 的 heroInfo 插槽,同时原样传入插槽属性。
// .vuepress/config.ts
import { getDirname, path } from "@vuepress/utils";
import { defineUserConfig } from "vuepress";

const __dirname = getDirname(import.meta.url);

export default defineUserConfig({
  // ...

  alias: {
    "@theme-hope/modules/blog/components/BlogHero": path.resolve(
      __dirname,
      "./components/BlogHero.vue"
    ),
  },
});

<!-- .vuepress/components/BlogHero.vue -->
<script setup lang="ts">
import BlogHero from "vuepress-theme-hope/blog/components/BlogHero.js";
import HitokotoBlogHero from "vuepress-theme-hope/presets/HitokotoBlogHero.js";
</script>

<template>
  <BlogHero>
    <template #heroInfo="heroInfo">
      <HitokotoBlogHero v-bind="heroInfo" />
    </template>
  </BlogHero>
</template>

必应壁纸+一言描述

<!-- .vuepress/components/BlogHero.vue -->
<script setup lang="ts">
    import BlogHero from "vuepress-theme-hope/blog/components/BlogHero.js";
    import BingHeroBackground from "vuepress-theme-hope/presets/BingHeroBackground.js";
    import HitokotoBlogHero from "vuepress-theme-hope/presets/HitokotoBlogHero.js";
    import CustomHeroBackground from "./CustomHeroBackground.vue";

</script>

<template>
    <BlogHero>
       
        <!--将博客主页的描述替换为随机的一言词句。 -->
        <template #heroInfo="heroInfo">
            <HitokotoBlogHero v-bind="heroInfo"/>
        </template>
         <!--必应壁纸,也可以用替换这个,默认就直接使用必应壁纸 -->
        <template #heroBg>
            <BingHeroBackground />
        </template>
    </BlogHero>
</template>

使用自定义的背景图

<!-- .vuepress/components/BlogHero.vue -->
<script setup lang="ts">
    import BlogHero from "vuepress-theme-hope/blog/components/BlogHero.js";
    import BingHeroBackground from "vuepress-theme-hope/presets/BingHeroBackground.js";
    import HitokotoBlogHero from "vuepress-theme-hope/presets/HitokotoBlogHero.js";
    import CustomHeroBackground from "./CustomHeroBackground.vue";

</script>

<template>
    <BlogHero>
<!-- 使用自定义壁纸-->
       <template #heroBg>
            <custom-hero-background/>
        </template>
        <!--将博客主页的描述替换为随机的一言词句。 -->
        <template #heroInfo="heroInfo">
            <HitokotoBlogHero v-bind="heroInfo"/>
        </template>
    </BlogHero>
</template>

.vuepress/components/CustomHeroBackground.vue 组件,每次加载不同的背景图

<template>
    <div class="hero-bkg" :style="{ 'background-image': 'url(' + gitBkgUrl + ')' }"></div>
</template>

<script>
    /**
     * 自定义 博客首页 背景图
     */
    import fs from "fs";
    import path from "path";
    export default {
        name: 'CustomHeroBackground',
        components: {},
        data () {
            return {
                //壁纸下载:https://wallpaper.ur1.fun/
                bkgUrlList:[
                    '/blogImage/blog_background0.jpg',
                    '/blogImage/blog_background1.jpg',
                    '/blogImage/blog_background2.jpg',
                    '/blogImage/blog_background3.png',
                    '/blogImage/blog_background4.png',
                    '/blogImage/blog_background5.png'
                ]
            }
        },
        // 初始化页面完成后
        mounted () {

        },
        computed: {
            gitBkgUrl() { // 计算属性
                var randomNum = Math.floor(Math.random() * 6);
                console.log(randomNum)
                console.log(this.bkgUrlList[randomNum])
                return this.bkgUrlList[randomNum];
            }
        },
        created () {
        },
        methods: {
            loadData () {

            },
        }
    }
</script>

<style lang="scss" scoped>
    .hero-bkg{
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        background-repeat:no-repeat;
        /*background-size: 100%100%;*/
        background-size: cover;
        background-position: center;
    }
</style>

主题文件说明

1. 图标

//方式一: 指定本地文件 (.vuepress/public/iconfont/iconfont.css)
iconAssets: '/iconfont/iconfont.css',
// 方式二:iconfont在线链接服务
iconAssets: ['//at.alicdn.com/t/c/font_4063270_szvla3jgl5.css','//at.alicdn.com/t/c/font_4073054_62p3wcbs8z4.css'],

2. 社交媒体

        // 社交媒体
        medias: {
            Email: "mailto:wangyilishihuan@163.com", // 注意邮件的打开方式 mailto:your-email@example.com
            Gitee: "https://gitee.com/mylishihuan",
            GitHub: "https://github.com/ghlishihuan",
            BiliBili: "https://space.bilibili.com/631039613",
            QQ: "http://wpa.qq.com/msgrd?v=3&uin=2413428881&site=qq&menu=yes",
            Wechat: "/assets/otherImg/Wechat.jpg",
        },

异常记录

vuepress-plugin-comment2: i A fallback Waline server is used for demo only. You should provide serverURL option yourself in production.

    // src/.vuepress/theme.ts
    comment: {                  // 评论服务配置
      provider: "Waline",
      serverURL: "https://waline.cailei.site/", /* https://waline-comment.vuejs.press 官方自己的地址,放着备用*/
      copyright: false,                          // 是否显示页脚Waline的版权信息(Powered by Waline v2.15.7)
      reaction: true,                            // 开启反应(你认为这篇文章怎么样?)
    },

本地图片破图

异常描述,点击其他页面后,在返回首页会导致首页的图片都出现破图了,原因是返回首页后 图片的请求url前缀变了

例如: 原本 http://localhost:8080/notes_book/images/home/WebGradients.jpgopen in new window

当访问demo文件路径 http://localhost:8080/notes_book/demo/

​ 在返回到首页时图片访问就会出现异常 变为 http://localhost:8080/notes_book/`demo`/images/home/WebGradients.jpgopen in new window

多出上一次请求的路径,导致图片破图

正确设置图片路径

文件实际位置 my-docs\src\.vuepress\public\images\home\Urbanfonts.png

使用相对路径 /images/home/Urbanfonts.png 切记最前面的需要添加 / 否则会异常