本文将介绍如何使用Vue3实现一个功能完整的文件管理系统,包含文件浏览、上传、下载、编辑和删除等核心功能。(文章最后附带效果图和源码下载)
一、项目概述
这个文件管理系统主要包含以下功能:
-
双模式切换:个人文件管理与公共文件浏览
-
文件树形结构展示
-
文件上传、下载、编辑和删除
-
批量操作功能
-
路径导航和搜索功能
二、项目结构
三、核心组件
-
文件系统数据结构:首先我们使用
buildFileSystem
函数将扁平的文件列表转换为树形结构:// utils/setFileTree.js export function buildFileSystem(files) { const root = { name: '', // 根节点名称(空字符串) path: '/', // 完整路径标识 children: [], // 子目录节点 isFolder: true, // 标记为文件夹 files: [], raw: null } // 路径映射:路径 → 节点对象 const pathMap = new Map().set('/', root) // 路径映射表(快速查找节点) files.forEach((file) => { // 示例路径 "/a/b/c" → ["a", "b", "c"] const pathParts = file.path.split('/').filter((p) => p !== '') let current = root pathParts.forEach((part, index) => { const isLast = index === pathParts.length - 1 // 判断是否为末级路径段 const currentPath = `/${pathParts.slice(0, index + 1).join('/')}` if (!pathMap.has(currentPath)) { const newNode = { name: part, // 节点名称(文件/文件夹,如 "a") path: currentPath, // 完整路径(如 "/a") children: [], // 子目录(仅文件夹有效) isFolder: !isLast, // 标记为文件夹(非末级路径) raw: isLast ? file : null, // 将文件节点赋值给 raw files: isLast ? [file] : [] // 末级路径存储文件对象 } // 补充逻辑 if (isLast) { newNode.files = [file] newNode.raw = file // 文件节点赋值 raw } else { newNode.raw = null // 明确文件夹节点无 raw } current.children.push(newNode) // 更新路径映射表 pathMap.set(currentPath, newNode) current = newNode } else { const existing = pathMap.get(currentPath) if (isLast) { existing.files.push(file) existing.raw = file // 更新已有文件的 raw } current = existing } }) }) return { root, pathMap } }
2、主组件FileBrowser
<template> <div class="file-browser"> <!-- 1. 顶部工具栏 --> <div class="top-toolbar"> <!-- 标题和模式切换按钮 --> </div> <!-- 2. 底部工具栏 --> <div class="bottom-toolbar"> <!-- 导航按钮和操作按钮 --> </div> <!-- 3. 文件列表区域 --> <div class="file-list-container"> <!-- 个人文件列表或公共文件列表 --> </div> <!-- 4. 编辑模态框 --> <EditModal v-if="editingFile" /> </div> </template>
主组件核心功能实现
// 模式切换
const toggleMode = () => {
isPublicMode.value = !isPublicMode.value;
selectedFiles.value.clear();
currentPage.value = 1;
};
// 文件导航
const goBack = () => {
const parts = currentPath.value.split('/').filter(p => p);
parts.pop();
currentPath.value = parts.length ? `/${parts.join('/')}` : '/';
};
const enterFolder = (path) => {
currentPath.value = path;
};
// 上传文件
const handleUpload = () => {
const input = document.createElement('input');
input.type = 'file';
input.onchange = (e) => {
const file = e.target.files[0];
console.log('上传文件:', file);
};
input.click();
};
// 删除文件
const handleDelete = (item) => {
if (confirm(`确认删除 ${item.path}?`)) {
console.log('删除文件:', item.path);
}
};
3、使用示例:在App.vue中使用组件
<!-- App.vue -->
<template>
<FileBrowser :fileSystem="fileSystem" :publicFiles="publicFiles" />
</template>
<script setup>
import { buildFileSystem } from '@/utils/setFileTree'
import FileBrowser from './components/FileBrowser.vue'
// 模拟数据(我这里使用静态数据代替接口数据)
const rawFiles = [
{
path: '/public/data/myfile.txt',
name: 'myfile.txt',
size: '1KB',
createDate: '2025-3-19 15:50:12',
creator: '小刘',
isPublic: true
},
{
path: '/private/docs/notes.txt',
name: 'notes.txt',
size: '1KB',
createDate: '2025-3-19 15:50:12',
creator: '小刘',
isPublic: true
}
]
// 构建文件系统
const fileSystem = buildFileSystem(rawFiles)
const publicFiles = rawFiles // 直接使用原始文件数组作为公共文件列表
</script>
<style scoped lang="scss">
body {
font-family: 'Arial', sans-serif;
background-color: #f0f0f0;
margin: 0;
padding: 20px;
}
</style>
项目实现了我的文件、公共文件两个板块之间的切换使用,以下是效果图: