Appearance
BizFileExplorer 文件资源管理器
文件资源管理器:面包屑路径导航(v-model 路径 id 序列)+ 当前层网格 / 列表双视图 + 名称搜索 + 单选高亮、双击打开(文件夹进入 / 文件 open)、悬浮操作(下载 / 删除事件外抛)。纯数据驱动(data 文件树注入)——上传、删除等动作由业务层执行后回写 data。网盘、素材库、附件管理的通用浏览区。
基础用法
交付资源
2 项
项目文档
3 项
README.md
3.1 KB
网格视图:双击进入文件夹,双击文件触发 open,悬浮出下载 / 删除。
<script setup lang="ts">
/** 场景:基础——网格视图 + 双击进入文件夹 */
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { BizFileExplorer } from 'vue3-ep-biz-lib'
import type { BizFileNode } from 'vue3-ep-biz-lib'
const path = ref<string[]>([])
const dayOf = (h: number): string => {
const d = new Date()
d.setHours(h, 10, 0, 0)
return d.toISOString()
}
const data: BizFileNode[] = [
{ id: 'docs', name: '项目文档', type: 'folder', updatedAt: dayOf(9), children: [
{ id: 'prd', name: '需求说明书 v2.docx', type: 'file', ext: 'docx', size: 284000, updatedAt: dayOf(9) },
{ id: 'api', name: '接口约定.pdf', type: 'file', ext: 'pdf', size: 1200000, updatedAt: dayOf(10) },
{ id: 'img', name: '原型截图', type: 'folder', updatedAt: dayOf(11), children: [
{ id: 'p1', name: '首页-终稿.png', type: 'file', ext: 'png', size: 860000, updatedAt: dayOf(11) },
] },
] },
{ id: 'res', name: '交付资源', type: 'folder', updatedAt: dayOf(8), children: [
{ id: 'pack', name: '交付包.zip', type: 'file', ext: 'zip', size: 52400000, updatedAt: dayOf(8) },
{ id: 'demo', name: '演示视频.mp4', type: 'file', ext: 'mp4', size: 156000000, updatedAt: dayOf(8) },
] },
{ id: 'readme', name: 'README.md', type: 'file', ext: 'md', size: 3200, updatedAt: dayOf(12) },
]
const onOpen = (node: BizFileNode): void => {
ElMessage.info(`打开文件:${node.name}`)
}
const onRemove = (node: BizFileNode): void => {
ElMessage.warning(`请求删除:${node.name}(demo 未回写数据)`)
}
</script>
<template>
<BizFileExplorer v-model="path" :data="data" show-upload @open="onOpen" @remove="onRemove" />
</template>
显示代码
列表视图
名称大小修改时间操作
四季度报表—2026-10-26 08:00
10月经营分析.xlsx957.0 KB2026-10-26 09:00
汇报材料.pptx6.5 MB2026-10-26 11:00
预算执行.pdf2.3 MB2026-10-26 10:00
view=list 行式布局,含大小与修改时间列(v-model:view 可切换)。<script setup lang="ts">
/** 场景:列表视图 + v-model:view 切换 */
import { ref } from 'vue'
import { BizFileExplorer } from 'vue3-ep-biz-lib'
import type { BizFileNode } from 'vue3-ep-biz-lib'
const view = ref<'grid' | 'list'>('list')
const path = ref<string[]>([])
const dayOf = (h: number): string => {
const d = new Date()
d.setHours(h, 0, 0, 0)
return d.toISOString()
}
const data: BizFileNode[] = [
{ id: 'q4', name: '四季度报表', type: 'folder', updatedAt: dayOf(8), children: [] },
{ id: 'r1', name: '10月经营分析.xlsx', type: 'file', ext: 'xlsx', size: 980000, updatedAt: dayOf(9) },
{ id: 'r2', name: '预算执行.pdf', type: 'file', ext: 'pdf', size: 2400000, updatedAt: dayOf(10) },
{ id: 'r3', name: '汇报材料.pptx', type: 'file', ext: 'pptx', size: 6800000, updatedAt: dayOf(11) },
]
</script>
<template>
<BizFileExplorer v-model="path" v-model:view="view" :data="data" />
</template>
显示代码
多级导航
集团文件
2 项
当前层级:根目录(路径 id 序列:根)
面包屑逐级进入 / 直接回跳任意层级,folder-change 外抛当前路径。
<script setup lang="ts">
/** 场景:多级导航——面包屑逐级进入与回跳 */
import { ref } from 'vue'
import { BizFileExplorer } from 'vue3-ep-biz-lib'
import type { BizFileNode } from 'vue3-ep-biz-lib'
const path = ref<string[]>([])
const current = ref('根目录')
const data: BizFileNode[] = [
{ id: 'company', name: '集团文件', type: 'folder', children: [
{ id: 'east', name: '华东大区', type: 'folder', children: [
{ id: 'sh', name: '上海分公司', type: 'folder', children: [
{ id: 'sh-q3', name: '三季度总结.docx', type: 'file', ext: 'docx', size: 220000 },
] },
{ id: 'hz', name: '杭州分公司', type: 'folder', children: [] },
] },
{ id: 'north', name: '华北大区', type: 'folder', children: [] },
] },
]
const onFolderChange = (folderPath: string[], folder: BizFileNode | null): void => {
current.value = folder === null ? '根目录' : folder.name
void folderPath
}
</script>
<template>
<div>
<BizFileExplorer v-model="path" :data="data" :searchable="false" @folder-change="onFolderChange" />
<p style="margin: 10px 0 0; font-size: 12px; color: var(--el-text-color-secondary)">
当前层级:{{ current }}(路径 id 序列:{{ path.length === 0 ? '根' : path.join(' → ') }})
</p>
</div>
</template>
显示代码
搜索
设计稿
0 项
品牌规范.pdf
878.9 KB
品牌色板.png
117.2 KB
图标库.svg
43.9 KB
字体包.zip
31.5 MB
按名称过滤当前层内容(文件夹优先排序)。
<script setup lang="ts">
/** 场景:搜索——当前层名称过滤 */
import { ref } from 'vue'
import { BizFileExplorer } from 'vue3-ep-biz-lib'
import type { BizFileNode } from 'vue3-ep-biz-lib'
const path = ref<string[]>([])
const data: BizFileNode[] = [
{ id: 'a', name: '设计稿', type: 'folder', children: [] },
{ id: 'b', name: '品牌规范.pdf', type: 'file', ext: 'pdf', size: 900000 },
{ id: 'c', name: '品牌色板.png', type: 'file', ext: 'png', size: 120000 },
{ id: 'd', name: '字体包.zip', type: 'file', ext: 'zip', size: 33000000 },
{ id: 'e', name: '图标库.svg', type: 'file', ext: 'svg', size: 45000 },
]
</script>
<template>
<BizFileExplorer v-model="path" :data="data" />
</template>
显示代码
事件
归档
0 项
报表.xlsx
488.3 KB
open / download / remove / upload / folder-change 全事件日志。
<script setup lang="ts">
/** 场景:全事件日志 */
import { ref } from 'vue'
import { BizFileExplorer } from 'vue3-ep-biz-lib'
import type { BizFileNode } from 'vue3-ep-biz-lib'
const path = ref<string[]>([])
const logs = ref<string[]>([])
const log = (text: string): void => {
logs.value.unshift(text)
if (logs.value.length > 6) logs.value.pop()
}
const data: BizFileNode[] = [
{ id: 'f1', name: '报表.xlsx', type: 'file', ext: 'xlsx', size: 500000 },
{ id: 'd1', name: '归档', type: 'folder', children: [] },
]
</script>
<template>
<div>
<BizFileExplorer
v-model="path"
:data="data"
show-upload
@open="(n: BizFileNode) => log(`open:${n.name}`)"
@download="(n: BizFileNode) => log(`download:${n.name}`)"
@remove="(n: BizFileNode) => log(`remove:${n.name}`)"
@upload="() => log('upload:请求上传到当前文件夹')"
@folder-change="(_p: string[], f: BizFileNode | null) => log(`folder-change:${f === null ? '根目录' : f.name}`)"
/>
<p v-for="(item, i) in logs" :key="i" style="margin: 6px 0 0; font-size: 12px; color: var(--el-text-color-secondary)">
{{ item }}
</p>
</div>
</template>
显示代码
自定义图标与操作
我的收藏
0 项
核心指标看板.xlsx
781.3 KB
月度复盘.pdf
1.7 MB
icon / actions 插槽接管卡片图标与悬浮操作。<script setup lang="ts">
/** 场景:icon / actions 插槽接管卡片图标与悬浮操作 */
import { ref } from 'vue'
import { ElIcon, ElMessage } from 'element-plus'
import { FolderOpened, Star } from '@element-plus/icons-vue'
import { BizFileExplorer } from 'vue3-ep-biz-lib'
import type { BizFileNode } from 'vue3-ep-biz-lib'
const path = ref<string[]>([])
const data: BizFileNode[] = [
{ id: 'fav', name: '我的收藏', type: 'folder', children: [] },
{ id: 'k1', name: '核心指标看板.xlsx', type: 'file', ext: 'xlsx', size: 800000 },
{ id: 'k2', name: '月度复盘.pdf', type: 'file', ext: 'pdf', size: 1800000 },
]
</script>
<template>
<BizFileExplorer v-model="path" :data="data">
<template #icon="{ node }">
<ElIcon :size="34" style="color: var(--el-color-warning)">
<FolderOpened v-if="node.type === 'folder'" />
<Star v-else />
</ElIcon>
</template>
<template #actions="{ node }">
<ElIcon title="收藏" style="cursor: pointer" @click.stop="ElMessage.info(`已收藏:${node.name}`)">
<Star />
</ElIcon>
</template>
</BizFileExplorer>
</template>
显示代码
列表视图导航
名称大小修改时间操作
财务凭证—2026-10-26 08:05
合同归档—2026-10-26 09:05
年度预算.xlsx527.3 KB2026-10-26 11:05
list 模式双击进出文件夹,大小与修改时间成列展示。
<script setup lang="ts">
/** 场景:列表视图导航——list 模式双击进出文件夹 */
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { BizFileExplorer } from 'vue3-ep-biz-lib'
import type { BizFileNode } from 'vue3-ep-biz-lib'
const view = ref<'grid' | 'list'>('list')
const path = ref<string[]>([])
const dayOf = (h: number): string => {
const d = new Date()
d.setHours(h, 5, 0, 0)
return d.toISOString()
}
const data: BizFileNode[] = [
{ id: 'contracts', name: '合同归档', type: 'folder', updatedAt: dayOf(9), children: [
{ id: 'c1', name: '2026 采购合同.pdf', type: 'file', ext: 'pdf', size: 1900000, updatedAt: dayOf(9) },
{ id: 'c2', name: '框架协议.docx', type: 'file', ext: 'docx', size: 320000, updatedAt: dayOf(10) },
] },
{ id: 'finance', name: '财务凭证', type: 'folder', updatedAt: dayOf(8), children: [] },
{ id: 'plan.xlsx', name: '年度预算.xlsx', type: 'file', ext: 'xlsx', size: 540000, updatedAt: dayOf(11) },
]
const onOpen = (node: BizFileNode): void => {
ElMessage.info(`预览文件:${node.name}`)
}
</script>
<template>
<BizFileExplorer v-model="path" v-model:view="view" :data="data" :searchable="false" @open="onOpen" />
</template>
显示代码
空态
空文件夹(empty 插槽自定义,覆盖默认 empty-text)
空文件夹占位,
empty 插槽接管(引导上传)。<script setup lang="ts">
/** 场景:空态——空文件夹与空数据(empty 插槽接管) */
import { ref } from 'vue'
import { ElButton } from 'element-plus'
import { BizFileExplorer } from 'vue3-ep-biz-lib'
import type { BizFileNode } from 'vue3-ep-biz-lib'
const data = ref<BizFileNode[]>([{ id: 'empty-folder', name: '待归档', type: 'folder', children: [] }])
const path = ref<string[]>(['empty-folder'])
</script>
<template>
<div>
<div style="margin-bottom: 10px">
<ElButton size="small" @click="path = []">返回根目录</ElButton>
</div>
<BizFileExplorer v-model="path" :data="data" :searchable="false">
<template #empty>
<div style="display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 20px 0">
<span style="font-size: 13px; color: var(--el-text-color-secondary)">空文件夹(empty 插槽自定义,覆盖默认 empty-text)</span>
<ElButton size="small" type="primary" plain>上传文件</ElButton>
</div>
</template>
</BizFileExplorer>
</div>
</template>
显示代码
Props
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| data | BizFileNode[] | [] | 文件树(根层列表,folder 含 children) |
| v-model | string[] | [] | 当前路径(根到当前文件夹 id 序列) |
| v-model:view | 'grid' | 'list' | 'grid' | 视图模式 |
| searchable | boolean | true | 名称搜索框 |
| show-upload | boolean | false | 上传按钮(emit upload) |
| empty-text | string | '当前文件夹为空' | 空态文案 |
| placeholder | string | '' | 搜索框占位(空则用默认文案) |
Events
| 事件名 | 参数 | 说明 |
|---|---|---|
| update:modelValue | (path: string[]) | 路径变化 |
| update:view | `(view: 'grid' | 'list')` |
| folder-change | (path, folder) | 进入 / 返回文件夹 |
| open | (node) | 双击打开文件 |
| download | (node) | 悬浮下载 |
| remove | (node) | 悬浮删除(业务回写 data) |
| upload | (folder) | 上传按钮(目标文件夹) |
Slots
| 插槽名 | 作用域 | 说明 |
|---|---|---|
| icon | { node } | 图标接管 |
| actions | { node } | 悬浮操作接管 |
| empty | — | 空态接管 |
Expose
| 名称 | 类型 | 说明 |
|---|---|---|
| navigate | (path: string[]) => void | 编程式进入路径 |
| getSelected | () => BizFileNode | null | 当前选中节点 |
| getCurrentFolder | () => BizFileNode | null | 当前文件夹 |