个人网站建站日记-集成Markdown编辑器

news/2024/12/15 13:39:40/文章来源:https://www.cnblogs.com/MrHanBlog/p/18607910

一次偶然的机会,我体验的到了markdown的便捷,于是乎,我就着手给我的网站闲蛋博客社区集成了Markdown,现在可以自由的切换Markdown与富文本编辑的使用了。这里我特此分享记录下安装使用的过程。

一、安装Markdown编辑器

这里我采用的是md-editor-v3编辑器,目前看来还是很好用的,安装方便,使用简单

二 pnpm安装 pnpm install md-editor-v3

注意,直接运行的是安装的最新版的,最新版本的使用的vue3.5以上,如果你低于3.5的版本,代码运行的时候可能会报错,所以安装的是其它的版本

pnpm install md-editor-v3@4.21.1

三、页面基本使用

话不多说,直接看代码

<template><MdEditor :autoFocus="true" v-model="textContent"  :toolbars="toolbars"></MdEditor>
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue';
import { MdEditor, DropdownToolbar, ToolbarNames, config } from 'md-editor-v3';
import 'md-editor-v3/lib/style.css';
const { checkImg } = useUpload();
const toolbars: ToolbarNames[] = ['bold','underline','italic','-','title','strikeThrough','sub','sup','quote','unorderedList','orderedList','task','-','codeRow','code','link','image','table','mermaid','katex','-','revoke','next','=','pageFullscreen','fullscreen','preview','htmlPreview','catalog','github'
];</script>

让后运行项目如下图
image

这样就可以了,但是我们看官网,它是可以支持切换主题的,那么怎实现呢。

四、编辑器切换主题

实现它就是去使用它的#defToolbars插槽,可以实现

实现切换预览主题

我这里只是默认使用它里面提供的几个主题,定义预览主题如下:

const previewThemeOptions = [{value: 'default',label: 'default'},{value: 'github',label: 'github'},{value: 'vuepress',label: 'vuepress'},{value: 'mk-cute',label: 'mk-cute'},{value: 'smart-blue',label: 'smart-blue'},{value: 'cyanosis',label: 'cyanosis'}
];

然后插槽里面的代码

<MdEditor :autoFocus="true" v-model="textContent" :previewTheme="previewThemeSelected":toolbars="toolbars"><template #defToolbars><DropdownToolbar title="预览主题" :visible="showPreviewTheme" :on-change="appendixPreviewThemeChanged"><template #overlay><el-select v-model="previewThemeSelected" size="small" style="width: 70px"@change="previewThemeChange"><el-option v-for="item in previewThemeOptions" :key="item.value" :label="item.label":value="item.value" /></el-select></template><template #trigger><el-icon class="md-editor-icon" :size="18"><Platform /></el-icon></template></DropdownToolbar></template></MdEditor>

同时在toolbars里面要加一个对应的索引位置,代表自己的工具栏
image

然后运行看下代码部分截图

default主题

image

github主题

image

smart-blue主题

image

以此类推,其它的主题我就不演示了

图片上传

图片上传要实现它的 @on-upload-img="onUploadImg"方法,参考代码如下,也可以参考官网的写法,比较简单

function onUploadImg(files, callback) {files.forEach((s) => {let file = s;let formData = new FormData();formData.append('file', file);uploadFileApi(formData).then((res) => {let arr = [];arr.push(res.urlPath);callback(arr);});});
}

内容超链接target属性

如果想实现target属性需要安装 markdown-it-link-attributes 插件,让后代码加入如下代码

import LinkAttr from 'markdown-it-link-attributes';
config({markdownItPlugins(plugins) {return [...plugins,{type: 'linkAttr',plugin: LinkAttr,options: {matcher(href: string) {return !href.startsWith('#');},attrs: {target: '_blank'}}}];}
});

应该没有什么还有补充了😲

五、页面如何渲染

上面搞的差不多后,就要实现文章页面渲染,我看网上的解决方法都是通过安装marked插件,然后通过它把markdown语法转成html,但是我没有使用。因为我看md-editor-v3已经实现了预览,并且非常简单。就是使用MdPreview组件就好了,也不需要额外安装调样式。

import { MdPreview } from 'md-editor-v3';
import 'md-editor-v3/lib/style.css';
  <MdPreview v-else v-model="articleContent" :previewTheme="预览主题" :codeTheme="代码主题" />

然后页面加载渲染就可以了
image

真实效果可以点这里 https://www.xiandanplay.com/article/view?id=17143377224138752&articleCategoryId=16078840161206272

六、代码示例

以下代码仅仅是我的业务代码,可以参考,具体的可以根据需要自行更改

<template><MdEditor :autoFocus="true" v-model="textContent" :previewTheme="previewThemeSelected":codeTheme="codeThemeSelected" @on-upload-img="onUploadImg" :toolbars="toolbars"><template #defToolbars><DropdownToolbar title="预览主题" :visible="showPreviewTheme" :on-change="appendixPreviewThemeChanged"><template #overlay><el-select v-model="previewThemeSelected" size="small" style="width: 70px"@change="previewThemeChange"><el-option v-for="item in previewThemeOptions" :key="item.value" :label="item.label":value="item.value" /></el-select></template><template #trigger><el-icon class="md-editor-icon" :size="18"><Platform /></el-icon></template></DropdownToolbar><DropdownToolbar title="代码主题" :visible="showCodeTheme" :on-change="appendixCodeThemeChanged"><template #overlay><el-select v-model="codeThemeSelected" size="small" style="width: 70px" @change="codeThemeChange"><el-option v-for="item in codeThemeOptions" :key="item.value" :label="item.label":value="item.value" /></el-select></template><template #trigger><el-icon class="md-editor-icon" :size="18"><Postcard /></el-icon></template></DropdownToolbar></template></MdEditor>
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue';
import { MdEditor, DropdownToolbar, ToolbarNames, config } from 'md-editor-v3';
import 'md-editor-v3/lib/style.css';
import { Marked } from 'marked';
import { useUpload } from '@/hooks/useUpload';
import { uploadFileApi } from '@/api/uploadFile';
import { CloudStorageType } from '@/utils/globalDeclare';
import LinkAttr from 'markdown-it-link-attributes';
config({markdownItPlugins(plugins) {return [...plugins,{type: 'linkAttr',plugin: LinkAttr,options: {matcher(href: string) {return !href.startsWith('#');},attrs: {target: '_blank'}}}];}
});
const { checkImg } = useUpload();
const marked = new Marked({ gfm: true });
const props = defineProps({codeTheme: {type: String,default: 'default'},previewTheme: {type: String,default: 'default'}
});
const toolbars: ToolbarNames[] = ['bold','underline','italic','-','title','strikeThrough','sub','sup','quote','unorderedList','orderedList','task','-','codeRow','code','link','image','table','mermaid','katex','-','revoke','next',0,1,'=','pageFullscreen','fullscreen','preview','htmlPreview','catalog','github'
];
const textContent = ref<string>();
const emit = defineEmits(['changeTheme']);
const showPreviewTheme = ref(false);
const showCodeTheme = ref(false);
const previewThemeOptions = [{value: 'default',label: 'default'},{value: 'github',label: 'github'},{value: 'vuepress',label: 'vuepress'},{value: 'mk-cute',label: 'mk-cute'},{value: 'smart-blue',label: 'smart-blue'},{value: 'cyanosis',label: 'cyanosis'}
];
const codeThemeOptions = [{value: 'atom',label: 'atom'},{value: 'a11y',label: 'a11y'},{value: 'github',label: 'github'},{value: 'gradient',label: 'gradient'},{value: 'kimbie',label: 'kimbie'},{value: 'paraiso',label: 'paraiso'},{value: 'qtcreator',label: 'qtcreator'},{value: 'stackoverflow',label: 'stackoverflow'}
];
const previewThemeSelected = ref<string>(props.previewTheme);
const codeThemeSelected = ref<string>(props.codeTheme);
init();
function init() {let themeStore = localStorage.getItem('mdv3_theme_store');if (themeStore) {let arr = themeStore.split('|');codeThemeSelected.value = arr[0];previewThemeSelected.value = arr[1];emit('changeTheme', {codeTheme: codeThemeSelected.value,previewTheme: previewThemeSelected.value});}
}
function previewThemeChange(selected) {setThemeStore('preview', selected);
}
function codeThemeChange(selected) {setThemeStore('code', selected);
}
function setThemeStore(themeType, themeSelected) {let theme: any = {};if (themeType == 'code') {localStorage.setItem('mdv3_theme_store',themeSelected + '|' + previewThemeSelected.value);theme.codeTheme = themeSelected;codeThemeSelected.value = themeSelected;theme.previewTheme = previewThemeSelected.value;} else {localStorage.setItem('mdv3_theme_store',codeThemeSelected.value + '|' + themeSelected);theme.codeTheme = codeThemeSelected.value;theme.previewTheme = themeSelected;previewThemeSelected.value = themeSelected;}emit('changeTheme', theme);
}function appendixPreviewThemeChanged() {if (showPreviewTheme.value) {showPreviewTheme.value = false;} else {showPreviewTheme.value = true;}
}
function appendixCodeThemeChanged() {if (showCodeTheme.value) {showCodeTheme.value = false;} else {showCodeTheme.value = true;}
}
function onUploadImg(files, callback) {files.forEach((s) => {let file = s;let result: boolean = checkImg(file, 2);if (result == false) {return;}let formData = new FormData();formData.append('file', file);formData.append('cloudStorageType', CloudStorageType.Qiniu);uploadFileApi(formData).then((res) => {let arr = [];arr.push(res.urlPath);callback(arr);});});
}
function setContent(content) {textContent.value = content;
}
function getTheme() {let theme = {codeTheme: codeThemeSelected.value,previewTheme: previewThemeSelected.value};return theme;
}
function getText() {const plainText = marked.parse(textContent.value).replace(/<\/?[^>]+(>|$)/g, '').trim();return plainText;
}
const getContent = () => {return textContent.value
};
defineExpose({ getText, getTheme, setContent, getContent });
</script>

作者:程序员奶牛
个人开源网站:https://www.xiandanplay.com
源码地址:https://gitee.com/MrHanchichi/xian-dan

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/853233.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

arbitrum 资产桥合约

资产桥的作用 Rollup 的主要流程中,实际上不包含资产桥,也就是说即使没有资产桥,L2依然能正常运行但是此时L1与L2在数据上是完全独立的两条链,L1不理解L2上的数据(L1只保存L2压缩后的数据,不理解数据),L2上也不知道L1上发生了什么(只能拿到区块高度等一些基本信息)。完…

鸿蒙NEXT开发案例:经纬度距离计算

【引言】 在鸿蒙NEXT平台上,我们可以轻松地开发出一个经纬度距离计算器,帮助用户快速计算两点之间的距离。本文将详细介绍如何在鸿蒙NEXT中实现这一功能,通过简单的用户界面和高效的计算逻辑,为用户提供便捷的服务。 【环境准备】 • 操作系统:Windows 10 • 开发工具:De…

C语言中0为假,正数和负数均为真

001、[b20223040323@admin2 test]$ ls test.c [b20223040323@admin2 test]$ cat test.c #include <stdio.h>int main(void) {int i,j,k; ## 三个变量 负数、正数和0i = -5;j = 8;k = 0;if(i){puts("xxxx");}if(j){puts("yyyy");}if(k){puts(&qu…

2024-2025-1(20241321)《计算机基础与程序设计》第十二周学习总结

这个作业属于哪个课程 <班级的链接>(2024-2025-1-计算机基础与程序设计)这个作业要求在哪里 <作业要求的链接>(2024-2025-1计算机基础与程序设计第十二周作业)这个作业的目标 <深刻学习C语言,反思一周学习,温故知新>作业正文 ... 本博客链接https://www.…

Jmeter接口测试-图片验证码的识别

Jmeter接口测试-对图片验证码的识别Jmeter接口测试-对验证码的识别 ## 大概说一下思路,以及方法,我的接口接口的返回值是img/base64编码的,我采用的是OCR Server识别,获取返回值,图片保存到本地,再图片转码base64,之后携带数据请求OCR识别。(网上的办法是接口这种base6…

yolo导出,动态batch,固定图片尺寸

当使用export,dynamic=True时,batch和尺寸都是动态的。若想只有batch动态

如何在PbootCMS中实现自动清理runtime缓存?

要在PbootCMS中实现自动清理runtime缓存,可以按照以下步骤操作:编辑控制器文件:打开文件 /apps/home/controller/ExtLabelController.php。 找到以下代码:php// 测试扩展单个标签 private function test() {$this->content = str_replace({pboot:userip}, get_user_ip()…

如何修改自动清理脚本的清理间隔时间?

如果你想修改自动清理脚本的清理间隔时间,可以在控制器文件中调整 expire_time 的计算方式。以下是具体步骤:编辑控制器文件:打开文件 /apps/home/controller/ExtLabelController.php。 找到以下代码:php// 自动会话清理脚本 public function clean_session() {check_dir(R…

如果修改权限后仍然提示“会话目录写入权限不足”,应该如何处理?

如果您已经按照建议修改了PbootCMS相关目录的权限,但仍然收到“会话目录写入权限不足”的提示,可能是由于以下几个原因导致的:服务器配置问题:某些服务器可能有特殊的权限管理机制,例如SELinux或AppArmor。这些机制可能会限制Web服务器对某些目录的写入权限,即使您已经设…

帝国CMS灵动标签调用栏目内容排除某些栏目方法

使用灵动标签中的条件来排除特定栏目内容 示例代码:[e:loop={0,20,5,1,id not in(7,9,15,16),newstime DESC}] <a href="<?=$bqsr[titleurl]?>"><?=$bqr[title]?></a> [/e:loop]通过 id not in(7,9,15,16) 条件排除指定的栏目ID【遇到问…

zblog函数GetCategoryByID:通过分类ID获取分类对象数据

函数位置:zblogphp.php文件,大约3300行。函数参数:$id:整数类型,要获取数据的分类ID。函数输出:返回一个对象,包含指定分类的所有值。示例:if ($zbp->GetCategoryByID(1)->ID != 0) {// 存在ID是1的分类echo $zbp->GetCategoryByID(1)->Name; }其他数据值:…

为什么在PbootCMS后台上传的缩略图会变得模糊?

在使用PbootCMS后台发布内容时,如果上传的缩略图变得模糊,这通常是由于PbootCMS默认的图片尺寸限制所致。PbootCMS为了保证网站的加载速度和性能,默认设置了缩略图的最大宽度和高度。当上传的图片超过这些限制时,系统会自动压缩图片,导致图片质量下降,从而显得模糊。以下…