文件管理树
用 tree-node 列配 customCell 实现一个文件管理树:单列 + headless(隐藏表头)的资源管理器列表,名称列整格自绘(文件夹 / 文件图标、行内重命名输入框),整格即拖拽热区。内置的「按层级缩进 + 引导线」与「箭头 / 懒加载 loading」分别经 stkTreeIndent、stkFoldIcon 两个插槽透传回来(注意它们是你的单元格组件的插槽,不是 StkTable 顶层插槽),由你决定渲染与否、摆在何处。
loading
文件管理能力
表格(自绘文件夹 / 文件图标)配齐了一套资源管理器式的交互,全部由 demo 自行拼装:
- 默认只展开第一层:
treeConfig.defaultExpandLevel = 1,不用defaultExpandAll全展开。 - 单击行展开 / 折叠:监听
cell-click,命中文件夹行时按当前展开态调setTreeExpand(row, { expand })取反。命中展开控件的点击不会触发cell-click,因此不会切换两次;行内重命名输入框上的点击要自行排除。 - 右键菜单:在
row-menu事件里弹出 ja-contextmenu。「新建文件 / 新建文件夹」只对文件夹行显示;「粘贴」常驻显示,复制后任意行都可点——粘到文件夹行 = 粘进该文件夹,粘到文件行 = 粘进该文件所在的目录;仅剪贴板为空、或剪切源已在目标目录内时置灰。 - 行内重命名:菜单点「重命名」后名称格内直接渲染
<input>,不新开弹窗(参考 VSCode);聚焦后选中主文件名、不含扩展名,Enter / 失焦提交,Esc 取消;空名视为取消,与同级同名则阻止提交,新建未提交的行取消即删除。 - 新建文件 / 文件夹:插入后按名称排序落到排序位,并立即进入行内重命名,提交前就是一个占位行。
- 位置只由排序决定(参考 VSCode):每层 children 按「文件夹优先 + 名称
localeCompare」排序,同文件夹内不能拖动调整顺序;新建、改名、移动、粘贴后都会重排,改名后行自动跳到新的排序位。 - 拖动只能跨文件夹:不用内置
dragRow把手列——整个名称格自带draggable,由单元格自己派发原生拖拽事件(dragstart/dragover/drop)。拖到文件夹行上移入该文件夹,拖到文件行上时按指针落在格子的上半区 / 下半区插到其前 / 后;同文件夹内的拖动不给出落点提示也不产生变化,把文件夹拖进自己的子孙同样被阻止。 - 悬浮 1s 自动展开:拖拽悬浮在未展开的文件夹上超过 1s 自动展开它,指针换行或离开即取消计时。
- 落点高亮:悬浮到文件夹上时,经共享的
dropTargetFolder高亮该文件夹自身与所有后代行的背景(自身再深一档),文件行落点则画插入线;放下或离开后高亮消失。编辑中的行临时关掉draggable,以免输入框无法选字。 - 剪切 / 复制 / 粘贴:剪贴板只记行引用。剪切的行置灰;粘贴时剪切为移动、复制为深拷贝(名字加
copy),落盘后按「文件夹优先 + 名称」重排。右键文件行粘贴即表示粘到该文件所在的目录(根层文件则粘到根)。粘贴完成后,落盘的那一行会调setHighlightDimRow做一次背景闪烁高亮,并滚动到可见位置。
契约
- 单元格根元素需
height: 100%; display: flex; align-items: center;:引导线画在缩进格内并撑满整行高,根元素若不是撑满行高的 flex 行,线会被截断。 - 自绘的展开控件必须带
data-stk-fold,每格只标记一个:标签等其它区域带上它也会变成点击热区。命中展开控件的点击不会再触发cell-click/cell-selected。 - 只想换箭头外观时,渲染
<slot name="stkFoldIcon" />即可拿回内置箭头(含懒加载 loading 占位与展开态旋转),无需自行判断展开状态。 - 图标宽于默认 16px 时覆盖
--tree-indent-width,让缩进格、控件占位格与引导线步长同步变化(示例取20px)。
单元格骨架
vue
<script lang="ts" setup>
import type { CustomCellProps } from 'stk-table-vue/src/StkTable/types/index';
import { StkTreeIndent } from 'stk-table-vue';
defineProps<CustomCellProps<any>>();
</script>
<template>
<div class="folder-cell">
<!-- 内置「按层级缩进 + 引导线」:用导出的 StkTreeIndent 组件,offset 把引导线校正到自绘图标中心 -->
<StkTreeIndent :level="level ?? 0" offset="6px" show-guide />
<!-- 自绘展开控件:必须带 data-stk-fold,开合两态由 treeExpanded 决定 -->
<span v-if="expandable" class="folder-cell__icon" data-stk-fold>{{ treeExpanded ? '▾' : '▸' }}</span>
<span v-else class="folder-cell__icon" />
<span>{{ cellValue }}</span>
</div>
</template>
<style>
.folder-cell {
height: 100%;
display: flex;
align-items: center;
}
.folder-cell__icon {
flex-shrink: 0;
width: var(--tree-indent-width);
text-align: center;
cursor: pointer;
}
</style>提示
列配置与内置树表一致,仍需 type: 'tree-node',只是渲染交给 customCell:
ts
const columns = [{ type: 'tree-node', title: 'Name', dataIndex: 'name', customCell: NameCell }];
const treeConfig = { defaultExpandLevel: 1, showGuide: true };树形基础用法与懒加载见树形表格。