即然是个人博客,那么绝对不能丢给自己一个大大的输入框敷衍了事。如果真是这样,现在就可以宣布项目到此结束了。如今没人享受用输入框写博客。作为一个有追求的程序员,作品就要紧跟潮流。
后来,Markdown 的崛起逐步改变了大家的排版方式。再加上我们其他几个项目都是面向程序员用户的,所以迁移到 md 上也是大势所趋。 ——Vditor文档
给个人博客嵌入MarkDownb编辑器,即便设备上没有支持MarkDown格式的文本编辑器,我们仍然能随时随地优雅的编写博客。这里的MarkDown组件,选择了Vditor,由思源笔记团队开源的浏览器端 Markdown 编辑器,MIT开源协议(几乎是最为宽松的开源协议),感谢思源团队的无私分享。
为了让我们的博客有良好的编辑和阅读体验,需要做两件工作:
- 封装Vditor编辑器组件
- 封装Vditor预览器组件
ps: 做好黑夜模式适配
在 src/components/目录下创建MarkDownEdit.vue、MarkDownRead.vue
封装Vditor编辑器组件
MarkDownEdit.vue
因为Vditor的初始化完成后,vue无法监听到Vditor对象内参数的变化,所以我们需要用一些小技巧来告诉框架刷新状态,以完成黑夜模式的变化。创建一个computed参数active,让其计算被pinia托管的参数active,一旦active变化,则调用setTheme()方法设置 主题。
这里先设置pinia
在src/stores/目录下创建themeSwitch.js,内容如下
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useThemeSwitch = defineStore('themeSwitch', () => {
const active = ref(false)
function changeActive(newActive){
this.active = newActive
}
return { active, changeActive }
})
然后编写MarkDownEdit.vue
<script setup >
import { ref, onMounted,computed } from 'vue';
import Vditor from 'vditor';
import 'vditor/dist/index.css';
const vditor = ref(null);
const props = defineProps(['active'])
const active = computed({
get(){
if(vditor.value!=null)
{
console.log(props.active)
const mode = props.active?'dark':'classic'
vditor.value.setTheme(mode,mode)
}
return props.active;
},
})
let content = ''
let width = 0;
let height = 0;
function ReInitVidor() {
width = window.innerWidth*0.92 < 600 ? 600 : window.innerWidth*0.92 ;
height = window.innerHeight * 0.9;
vditor.value = new Vditor('vditor', {
mode:'sv',
preview:{},
icon:'material',
height:height,
width:width,
placeholder:"君子藏器于身,待时而动",
counter:{
enable:true,
},
preview:{
actions:[]
},
input:(value) => {
content = value
},
after: () => {
// vditor.value is a instance of Vditor now and thus can be safely used here
vditor.value.setValue(content);
},
});
}
onMounted(() => {
window.addEventListener('resize', ReInitVidor)
ReInitVidor();
});
</script>
<template>
<div style="display: flex;flex-direction: row;justify-content: center;">
<!-- 一定要在html的部分插入active,
vue框架才会去真正监听并计算active参数-->
<div hidden>active: {{ active }}</div>
<div id="vditor" ></div>
</div>
</template>
封装Vditor预览器组件
<template>
<div>
<div hidden>{{active}} </div>
<div id="vditor" ></div>
</div>
</template>
<script setup >
import { onMounted,computed, } from 'vue';
import Vditor from 'vditor';
import 'vditor/dist/index.css';
const props = defineProps(['active'])
let active = computed({
get(){
return props.active;
},
})
const IPreviewOptions = {
theme:{current:props.active?"dark":"light"},
mode:"dark",
speech:{"enable":true}
}
const mdStr=`## 💡 简介
[Vditor](https://b3log.org/vditor) 是一款浏览器端的 Markdown 编辑器,支持所见即所得(富文本)、即时渲染(类似 Typora)和分屏预览模式。它使用 TypeScript 实现,支持原生 JavaScript、Vue、React、Angular,提供[桌面版](https://b3log.org/siyuan)。`
function ReInitVidor() {
Vditor.preview(
document.getElementById('vditor'),
mdStr,IPreviewOptions);
}
onMounted(() => {
addEventListener("resize",ReInitVidor)
ReInitVidor();
});
</script>
使用组件
在src/views/目录下创建BlogEditView.vue、BlogReadView.vue文件
BlogEditView.vue
<script setup>
import MarkDownEdit from '../components/MarkDownEdit.vue';
import { useThemeSwitch } from '../stores/themeSwitch';
const themeSwitcher = useThemeSwitch()
</script>
<template>
<mark-down-edit :active="themeSwitcher.active"></mark-down-edit>
</template>
BlogReadView.vue
因为vditor.preview没有提供setTheme这种好用的函数。所以我们在active值改变后,要告诉vue框架强制刷新组件。这里使用:key=“”参数,组件会监听key参数是否变化,变化则刷新组件。
<script setup>
import MarkDownRead from '../components/MarkDownRead.vue';
import { NSpace } from 'naive-ui';
import { useThemeSwitch } from '../stores/themeSwitch';
const themeSwitcher = useThemeSwitch()
</script>
<template>
<n-space
style="height: 100%;"
justify="center"
size="large"
>
<mark-down-read class="blog-read-preview" :key="themeSwitcher.active" :active="themeSwitcher.active"></mark-down-read>
</n-space>
</template>
<style>
.blog-read-preview{
margin-inline: 15vw;
max-width: 900px;
}
</style>
最终效果
编辑器
预览器
暂时的休息
当前只是一种简单的封装,方便组织前端代码结构,在实现功能时,会按需进一步修改相关代码。