feat: 实现保存,显示隐藏目录等功能
This commit is contained in:
parent
f514f885df
commit
8895ddf9a4
@ -60,6 +60,7 @@
|
|||||||
|
|
||||||
1. `npm install md-editor-v3 --save`
|
1. `npm install md-editor-v3 --save`
|
||||||
2. 在 src/components/MainEditor.vue 组件里使用 md-editor-v3 组件
|
2. 在 src/components/MainEditor.vue 组件里使用 md-editor-v3 组件
|
||||||
|
3. 实现保存功能;自定义工具栏实现显示/隐藏目录以及发布等功能
|
||||||
|
|
||||||
### 调试应用
|
### 调试应用
|
||||||
|
|
||||||
|
|||||||
25
src/App.vue
25
src/App.vue
@ -12,7 +12,7 @@
|
|||||||
<template #right>
|
<template #right>
|
||||||
<div ref="splitRight" class="split-right">
|
<div ref="splitRight" class="split-right">
|
||||||
<MainEditor ref="mainEditor" v-model:markdownCode="markdownCode"
|
<MainEditor ref="mainEditor" v-model:markdownCode="markdownCode"
|
||||||
:save="writeFileContent">
|
v-model:leftSidebarState="leftSidebarState" :save="writeFileContent">
|
||||||
</MainEditor>
|
</MainEditor>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -36,24 +36,35 @@ async function greet() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 使用 Split 组件动态控制页面左右布局
|
// 使用 Split 组件动态控制页面左右布局
|
||||||
const split = ref(0.2);
|
const defaultSplit = 0.15; // 默认左侧边栏和右侧区域的比例为 1.5:8.5
|
||||||
|
const split = ref(defaultSplit);
|
||||||
const splitTrigger = useTemplateRef('splitTrigger');
|
const splitTrigger = useTemplateRef('splitTrigger');
|
||||||
const splitRight = useTemplateRef('splitRight');
|
const splitRight = useTemplateRef('splitRight');
|
||||||
const splitRightWidth = ref(0);
|
const splitRightWidth = ref(0);
|
||||||
const hiddenSplitLeft = ref("");
|
const hiddenSplitLeft = ref('');
|
||||||
|
const leftSidebarState = ref('open');
|
||||||
watch(split, (newSplit) => {
|
watch(split, (newSplit) => {
|
||||||
splitRightWidth.value = splitRight.value.offsetWidth;
|
splitRightWidth.value = splitRight.value.offsetWidth;
|
||||||
// 当 split 小于某个值时,隐藏左边布局
|
// 当 split 小于某个值时,隐藏左边布局
|
||||||
if (newSplit < 0.05) {
|
if (newSplit < 0.05) {
|
||||||
if (hiddenSplitLeft.value == "") {
|
leftSidebarState.value = 'close';
|
||||||
hiddenSplitLeft.value = "hidden"
|
if (hiddenSplitLeft.value == '') {
|
||||||
|
hiddenSplitLeft.value = 'hidden';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (hiddenSplitLeft.value == "hidden") {
|
leftSidebarState.value = 'open';
|
||||||
hiddenSplitLeft.value = ""
|
if (hiddenSplitLeft.value == 'hidden') {
|
||||||
|
hiddenSplitLeft.value = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
watch(leftSidebarState, (state) => {
|
||||||
|
if (state == 'open') {
|
||||||
|
split.value = defaultSplit;
|
||||||
|
} else {
|
||||||
|
split.value = 0;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// 监听根目录路径。如果之前已经选过目录,初始界面直接加载该目录
|
// 监听根目录路径。如果之前已经选过目录,初始界面直接加载该目录
|
||||||
const rootFolderPath = ref(localStorage.getItem('rootPathOfFolderTree') || "");
|
const rootFolderPath = ref(localStorage.getItem('rootPathOfFolderTree') || "");
|
||||||
|
|||||||
@ -2,7 +2,27 @@
|
|||||||
<Split v-model="split">
|
<Split v-model="split">
|
||||||
<template #left>
|
<template #left>
|
||||||
<MdEditor ref="editorRef" v-model="editorState.text" :id="editorState.id" :theme="editorState.theme"
|
<MdEditor ref="editorRef" v-model="editorState.text" :id="editorState.id" :theme="editorState.theme"
|
||||||
:style="{ height: editorState.height }" :toolbars="editorState.toolbars" :toolbarsExclude="['github']">
|
:style="{ height: editorState.height }" :toolbars="editorState.toolbars" :toolbarsExclude="['github']"
|
||||||
|
@onSave="onSave" @onHtmlChanged="getPreviewedHTML">
|
||||||
|
<template #defToolbars>
|
||||||
|
<NormalToolbar :title="leftSidebarState == 'open' ? '隐藏文件树' : '显示文件树'" @onClick="toggleLeftSideBar">
|
||||||
|
<template #trigger>
|
||||||
|
<Icon v-if="leftSidebarState == 'open'" type="ios-arrow-dropleft" size="22" />
|
||||||
|
<Icon v-else type="ios-arrow-dropright" size="22" />
|
||||||
|
</template>
|
||||||
|
</NormalToolbar>
|
||||||
|
<NormalToolbar :title="split == 1 ? '显示目录' : '隐藏目录'" @onClick="toggleCatalog">
|
||||||
|
<template #trigger>
|
||||||
|
<Icon :class="split == 1 ? '' : 'md-editor-toolbar-active'" type="ios-list-box-outline"
|
||||||
|
size="22" />
|
||||||
|
</template>
|
||||||
|
</NormalToolbar>
|
||||||
|
<NormalToolbar title="发布文章" @onClick="publish">
|
||||||
|
<template #trigger>
|
||||||
|
<Icon class="md-editor-icon" type="md-cloud-upload" size="22" />
|
||||||
|
</template>
|
||||||
|
</NormalToolbar>
|
||||||
|
</template>
|
||||||
</MdEditor>
|
</MdEditor>
|
||||||
</template>
|
</template>
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
@ -18,7 +38,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import 'md-editor-v3/lib/style.css';
|
import 'md-editor-v3/lib/style.css';
|
||||||
import { MdEditor, MdCatalog } from 'md-editor-v3';
|
import { MdEditor, MdCatalog, NormalToolbar } from 'md-editor-v3';
|
||||||
import { ref, reactive, watch } from "vue";
|
import { ref, reactive, watch } from "vue";
|
||||||
import { Message } from 'view-ui-plus'
|
import { Message } from 'view-ui-plus'
|
||||||
|
|
||||||
@ -28,6 +48,11 @@ const props = defineProps({
|
|||||||
required: false,
|
required: false,
|
||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
|
leftSidebarState: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: 'open'
|
||||||
|
},
|
||||||
save: {
|
save: {
|
||||||
type: Function,
|
type: Function,
|
||||||
required: false,
|
required: false,
|
||||||
@ -39,10 +64,12 @@ const props = defineProps({
|
|||||||
|
|
||||||
const emit = defineEmits([
|
const emit = defineEmits([
|
||||||
'update:markdownCode',
|
'update:markdownCode',
|
||||||
|
'update:leftSidebarState',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 定义布局,主要用于在右边显示文章目录
|
// 定义布局,主要用于在右边显示文章目录
|
||||||
const split = ref(0.8);
|
const split = ref(1);
|
||||||
|
const defaultCatalogSplit = 0.2; // 默认目录和编辑器的比例为 8:2
|
||||||
const hiddenSplitRight = split.value == 1 ? ref('hidden') : ref('');
|
const hiddenSplitRight = split.value == 1 ? ref('hidden') : ref('');
|
||||||
watch(split, (newSplit) => {
|
watch(split, (newSplit) => {
|
||||||
if (newSplit > 0.95) {
|
if (newSplit > 0.95) {
|
||||||
@ -65,6 +92,9 @@ const editorState = reactive({
|
|||||||
height: '100vh',
|
height: '100vh',
|
||||||
text: props.markdownCode,
|
text: props.markdownCode,
|
||||||
toolbars: [
|
toolbars: [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
'-',
|
||||||
'bold',
|
'bold',
|
||||||
'underline',
|
'underline',
|
||||||
'italic',
|
'italic',
|
||||||
@ -89,6 +119,7 @@ const editorState = reactive({
|
|||||||
'revoke',
|
'revoke',
|
||||||
'next',
|
'next',
|
||||||
'save',
|
'save',
|
||||||
|
2,
|
||||||
'=',
|
'=',
|
||||||
'prettier',
|
'prettier',
|
||||||
'pageFullscreen',
|
'pageFullscreen',
|
||||||
@ -110,6 +141,41 @@ watch(() => editorState.text, (newCode) => {
|
|||||||
emit('update:markdownCode', newCode);
|
emit('update:markdownCode', newCode);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const toggleLeftSideBar = () => {
|
||||||
|
if (props.leftSidebarState == 'open') {
|
||||||
|
emit('update:leftSidebarState', 'close');
|
||||||
|
} else {
|
||||||
|
emit('update:leftSidebarState', 'open');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleCatalog = () => {
|
||||||
|
if (split.value < 1) {
|
||||||
|
split.value = 1;
|
||||||
|
} else {
|
||||||
|
split.value = 1 - defaultCatalogSplit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSave = (v, h) => {
|
||||||
|
// 调用 save 方法保存代码(参数 v 为 markdown code)
|
||||||
|
props.save(v);
|
||||||
|
|
||||||
|
// 使用 h 可以在保存时直接获取 html
|
||||||
|
// h.then((html) => {
|
||||||
|
// console.log(html);
|
||||||
|
// });
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPreviewedHTML = (html) => {
|
||||||
|
console.log(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
const publish = () => {
|
||||||
|
// TODO 调用接口将 markdown 源码或者 HTML 代码发布到云端
|
||||||
|
Message.warning('抱歉,该功能暂未开放');
|
||||||
|
}
|
||||||
|
|
||||||
// 对父组件暴露数据或方法
|
// 对父组件暴露数据或方法
|
||||||
defineExpose({})
|
defineExpose({})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user