- 拆分 FileSystem.vue 为模块化组件架构 - 新增 Markdown Mermaid 图表渲染支持 - 新增 180+ 编程语言代码高亮 - 修复编辑/预览模式切换渲染问题 - 优化亮色/暗色模式主题适配 - 新增 TypeScript 类型定义
274 lines
6.2 KiB
JavaScript
274 lines
6.2 KiB
JavaScript
/**
|
|
* 导航和路径管理 composable
|
|
*
|
|
* @module composables/useNavigation
|
|
* @description 封装文件系统的导航历史、路径操作等逻辑
|
|
*/
|
|
|
|
import { ref, computed } from 'vue'
|
|
import { Message } from '@arco-design/web-vue'
|
|
|
|
/**
|
|
* 路径历史 localStorage 键
|
|
*/
|
|
const STORAGE_KEY_PATH_HISTORY = 'app-filesystem-path-history'
|
|
|
|
/**
|
|
* 导航管理 composable
|
|
* @param {Object} options - 配置选项
|
|
* @param {Ref<string>} options.filePath - 当前路径 ref
|
|
* @param {Function} options.onListDirectory - 列出目录的函数
|
|
* @param {Function} options.onExitZipMode - 退出 ZIP 模式的函数
|
|
* @returns {UseNavigationReturn} 导航操作 API
|
|
*/
|
|
export function useNavigation(options = {}) {
|
|
const {
|
|
filePath,
|
|
onListDirectory,
|
|
onExitZipMode,
|
|
} = options
|
|
|
|
// ========== 导航历史记录(支持后退/前进) ==========
|
|
|
|
/**
|
|
* 导航历史栈
|
|
* @type {Ref<Array<string>>}
|
|
*/
|
|
const navHistory = ref([])
|
|
|
|
/**
|
|
* 当前在历史栈中的位置
|
|
* @type {Ref<number>}
|
|
*/
|
|
const navIndex = ref(-1)
|
|
|
|
/**
|
|
* 是否正在导航(防止重复记录)
|
|
* @type {Ref<boolean>}
|
|
*/
|
|
const isNavigating = ref(false)
|
|
|
|
/**
|
|
* 路径历史记录(用于下拉列表)
|
|
* @type {Ref<Array<string>>}
|
|
*/
|
|
const pathHistory = ref([])
|
|
|
|
// ========== 计算属性 ==========
|
|
|
|
/**
|
|
* 是否可以后退
|
|
*/
|
|
const canGoBack = computed(() => navIndex.value > 0)
|
|
|
|
/**
|
|
* 是否可以前进
|
|
*/
|
|
const canGoForward = computed(() => navIndex.value < navHistory.value.length - 1)
|
|
|
|
// ========== 导航操作 ==========
|
|
|
|
/**
|
|
* 添加到路径历史记录
|
|
* @param {string} path - 路径
|
|
*/
|
|
const addToHistory = (path) => {
|
|
if (!path || path === filePath.value) return
|
|
|
|
// 去重:如果路径已在历史中,先删除
|
|
const index = pathHistory.value.indexOf(path)
|
|
if (index > -1) {
|
|
pathHistory.value.splice(index, 1)
|
|
}
|
|
|
|
// 添加到开头
|
|
pathHistory.value.unshift(path)
|
|
|
|
// 限制历史记录数量
|
|
if (pathHistory.value.length > 50) {
|
|
pathHistory.value = pathHistory.value.slice(0, 50)
|
|
}
|
|
|
|
// 持久化
|
|
try {
|
|
localStorage.setItem(STORAGE_KEY_PATH_HISTORY, JSON.stringify(pathHistory.value))
|
|
} catch (e) {
|
|
// 忽略 localStorage 错误
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 推送到导航历史栈
|
|
* @param {string} path - 路径
|
|
*/
|
|
const pushNav = (path) => {
|
|
if (isNavigating.value) {
|
|
return
|
|
}
|
|
|
|
// 如果当前位置不在历史末尾,删除后续历史
|
|
if (navIndex.value < navHistory.value.length - 1) {
|
|
navHistory.value = navHistory.value.slice(0, navIndex.value + 1)
|
|
}
|
|
|
|
// 添加到历史
|
|
navHistory.value.push(path)
|
|
navIndex.value = navHistory.value.length - 1
|
|
|
|
// 同时添加到路径历史
|
|
addToHistory(path)
|
|
}
|
|
|
|
/**
|
|
* 后退
|
|
* @returns {Promise<boolean>} 是否成功
|
|
*/
|
|
const goBack = async () => {
|
|
if (!canGoBack.value) {
|
|
return false
|
|
}
|
|
|
|
isNavigating.value = true
|
|
try {
|
|
navIndex.value--
|
|
const path = navHistory.value[navIndex.value]
|
|
await onListDirectory(path)
|
|
return true
|
|
} catch (error) {
|
|
Message.error(`后退失败: ${error.message || error}`)
|
|
return false
|
|
} finally {
|
|
isNavigating.value = false
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 前进
|
|
* @returns {Promise<boolean>} 是否成功
|
|
*/
|
|
const goForward = async () => {
|
|
if (!canGoForward.value) {
|
|
return false
|
|
}
|
|
|
|
isNavigating.value = true
|
|
try {
|
|
navIndex.value++
|
|
const path = navHistory.value[navIndex.value]
|
|
await onListDirectory(path)
|
|
return true
|
|
} catch (error) {
|
|
Message.error(`前进失败: ${error.message || error}`)
|
|
return false
|
|
} finally {
|
|
isNavigating.value = false
|
|
}
|
|
}
|
|
|
|
// ========== 路径操作 ==========
|
|
|
|
/**
|
|
* 路径选择(从下拉列表)
|
|
* @param {string} value - 选中的路径
|
|
*/
|
|
const onPathSelect = (value) => {
|
|
if (value && value !== filePath.value) {
|
|
goToPath(value)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 路径输入框回车事件
|
|
*/
|
|
const onPathEnter = () => {
|
|
const path = filePath.value?.trim()
|
|
if (path) {
|
|
goToPath(path)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 跳转到指定路径
|
|
* @param {string} path - 目标路径
|
|
* @returns {Promise<boolean>} 是否成功
|
|
*/
|
|
const goToPath = async (path) => {
|
|
if (!path) {
|
|
return false
|
|
}
|
|
|
|
// 退出 ZIP 模式
|
|
if (onExitZipMode) {
|
|
onExitZipMode()
|
|
}
|
|
|
|
return await onListDirectory(path)
|
|
}
|
|
|
|
/**
|
|
* 浏览目录(打开系统文件选择对话框)
|
|
*/
|
|
const browseDirectory = async () => {
|
|
Message.info('请手动输入目录路径')
|
|
}
|
|
|
|
// ========== 初始化 ==========
|
|
|
|
/**
|
|
* 加载路径历史记录
|
|
*/
|
|
const loadPathHistory = () => {
|
|
try {
|
|
const saved = localStorage.getItem(STORAGE_KEY_PATH_HISTORY)
|
|
if (saved) {
|
|
pathHistory.value = JSON.parse(saved)
|
|
}
|
|
} catch (e) {
|
|
console.warn('[useNavigation] 加载路径历史失败:', e)
|
|
}
|
|
}
|
|
|
|
// 初始化
|
|
loadPathHistory()
|
|
|
|
return {
|
|
// 状态
|
|
navHistory,
|
|
navIndex,
|
|
isNavigating,
|
|
pathHistory,
|
|
canGoBack,
|
|
canGoForward,
|
|
|
|
// 方法
|
|
addToHistory,
|
|
pushNav,
|
|
goBack,
|
|
goForward,
|
|
onPathSelect,
|
|
onPathEnter,
|
|
goToPath,
|
|
browseDirectory,
|
|
loadPathHistory,
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @typedef {Object} UseNavigationReturn
|
|
* @property {Ref<Array<string>>} navHistory - 导航历史栈
|
|
* @property {Ref<number>} navIndex - 当前在历史栈中的位置
|
|
* @property {Ref<boolean>} isNavigating - 是否正在导航
|
|
* @property {Ref<Array<string>>} pathHistory - 路径历史记录(下拉列表)
|
|
* @property {ComputedRef<boolean>} canGoBack - 是否可以后退
|
|
* @property {ComputedRef<boolean>} canGoForward - 是否可以前进
|
|
* @property {Function} addToHistory - 添加到路径历史记录
|
|
* @property {Function} pushNav - 推送到导航历史栈
|
|
* @property {Function} goBack - 后退
|
|
* @property {Function} goForward - 前进
|
|
* @property {Function} onPathSelect - 路径选择
|
|
* @property {Function} onPathEnter - 路径输入框回车事件
|
|
* @property {Function} goToPath - 跳转到指定路径
|
|
* @property {Function} browseDirectory - 浏览目录
|
|
* @property {Function} loadPathHistory - 加载路径历史记录
|
|
*/
|