160 lines
5.1 KiB
Vue
160 lines
5.1 KiB
Vue
<script setup>
|
||
import { ref, watch, useTemplateRef, onMounted, onUnmounted } from "vue";
|
||
import { invoke } from "@tauri-apps/api/core";
|
||
import { readTextFile, writeTextFile } from '@tauri-apps/plugin-fs';
|
||
import { Message } from 'view-ui-plus'
|
||
import MarkdownEditor from './components/MarkdownEditor.vue'
|
||
import SelectFolder from './components/SelectFolder.vue'
|
||
import FolderTree from './components/FolderTree.vue'
|
||
|
||
// 原始示例数据,仅供参考
|
||
const greetMsg = ref("");
|
||
const name = ref("");
|
||
async function greet() {
|
||
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
|
||
greetMsg.value = await invoke("greet", { name: name.value });
|
||
}
|
||
|
||
const markdownRef = ref(null);
|
||
// 矫正 markdown 编辑器的高度
|
||
function reloadEditorHeight() {
|
||
markdownRef.value.resetHeight(window.innerHeight)
|
||
}
|
||
// 矫正 markdown 编辑器的宽度
|
||
function reloadEditorWidth() {
|
||
// 可以使用 splitRight.value.offsetWidth 也可以使用 100% 来调整
|
||
const width = splitRight.value.offsetWidth
|
||
markdownRef.value.resetWidth("100%")
|
||
}
|
||
// 监听页面宽度和高度,调整 markdown 编辑器的高宽度
|
||
const handleWindowResize = () => {
|
||
reloadEditorHeight()
|
||
reloadEditorWidth()
|
||
}
|
||
onMounted(() => window.addEventListener('resize', handleWindowResize))
|
||
onUnmounted(() => window.removeEventListener('resize', handleWindowResize))
|
||
|
||
// 动态控制页面左右布局
|
||
const split = ref(0.2)
|
||
const hiddenSplitRight = ref("")
|
||
const splitRight = useTemplateRef('splitRight')
|
||
watch(split, (newSplit, oldSplit) => {
|
||
// 当 split 小于某个值时,隐藏左边布局
|
||
if (newSplit < 0.05) {
|
||
split.value = 0.01
|
||
if (hiddenSplitRight.value == "") {
|
||
hiddenSplitRight.value = "hidden"
|
||
}
|
||
} else {
|
||
if (hiddenSplitRight.value == "hidden") {
|
||
hiddenSplitRight.value = ""
|
||
}
|
||
}
|
||
|
||
// 动态调整 MarkdownEditor 的宽度。如果不执行 reset 的话,CodeMirror 内部编辑器不会自适应宽度
|
||
reloadEditorWidth()
|
||
})
|
||
|
||
// 如果之前已经选过目录,那么直接加载该目录
|
||
const rootPathOfFolderTree = ref(localStorage.getItem('rootPathOfFolderTree') || "")
|
||
function changeRootPath(newRootPath) {
|
||
localStorage.setItem('rootPathOfFolderTree', newRootPath)
|
||
rootPathOfFolderTree.value = newRootPath
|
||
}
|
||
|
||
// <SelectFolder> 选择目录后赋值给 folderTreeData,然后再传递给 <FolderTree>
|
||
const folderTreeData = ref(null)
|
||
function showFileTree(treeData) {
|
||
folderTreeData.value = treeData
|
||
}
|
||
|
||
// <FolderTree> 完成文件树渲染后,点击文件得到 currentFilePath
|
||
// 读取 currentFilePath 的文件内容,填充到 MarkdownEditor 之中
|
||
const currentFilePath = ref("");
|
||
const loadingCurrentFile = ref(true);
|
||
async function loadFileContent(fileNodeData) {
|
||
console.log(fileNodeData)
|
||
const filePath = fileNodeData.path
|
||
currentFilePath.value = filePath
|
||
loadingCurrentFile.value = true
|
||
await readFileContent(filePath)
|
||
}
|
||
async function readFileContent(filePath) {
|
||
try {
|
||
markdownRef.value.setMarkdownCode(await readTextFile(filePath))
|
||
Message.success('已读取文件内容,并加载到编辑器中:' + filePath);
|
||
} catch (err) {
|
||
Message.error('文件读取失败:' + err);
|
||
}
|
||
}
|
||
async function writeFileContent() {
|
||
try {
|
||
// 如果触发当前事件,是因为刚点击并加载了某个文件内容,则不执行写文件操作
|
||
if (!loadingCurrentFile.value) {
|
||
await writeTextFile(currentFilePath.value, markdownRef.value.getMarkdownCode())
|
||
}
|
||
loadingCurrentFile.value = false
|
||
} catch (err) {
|
||
Message.error('文件更新失败:' + err);
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<div>
|
||
<Split v-model="split">
|
||
<template #left>
|
||
<div class="split-left">
|
||
<SelectFolder :class="hiddenSplitRight" :rootPath="rootPathOfFolderTree" @update:rootPath="changeRootPath"
|
||
@folder-selected="showFileTree" />
|
||
<FolderTree :class="hiddenSplitRight" :treeData="folderTreeData" :expandLevel="1"
|
||
:specifyFileSuffix="['md']" @file-selected="loadFileContent" />
|
||
</div>
|
||
</template>
|
||
<template #trigger>
|
||
<div class="split-trigger"></div>
|
||
</template>
|
||
<template #right>
|
||
<div ref="splitRight" class="split-right">
|
||
<MarkdownEditor ref="markdownRef" width="100%" height="100%" markdownCode="# hello tauri"
|
||
:onload="reloadEditorHeight" :onfullscreenExit="handleWindowResize" @update:markdownCode="writeFileContent" />
|
||
</div>
|
||
</template>
|
||
</Split>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
body {
|
||
overflow: hidden;
|
||
/* 禁用所有方向滚动 */
|
||
}
|
||
|
||
.split-left {
|
||
height: 100vh;
|
||
border-right: 1px solid #dcdee2;
|
||
overflow-x: hidden;
|
||
overflow-y: auto;
|
||
scrollbar-width: none;
|
||
}
|
||
|
||
.split-trigger {
|
||
width: 5px;
|
||
height: 100vh;
|
||
background-color: gray;
|
||
}
|
||
|
||
.split-trigger:hover {
|
||
cursor: ew-resize;
|
||
}
|
||
|
||
.split-right {
|
||
margin-left: 5px;
|
||
}
|
||
|
||
.hidden {
|
||
display: none;
|
||
}
|
||
</style>
|
||
<style></style>
|