@pierre/trees 文件树交互配置指南:搜索、重命名、拖拽与 Git 状态实战

发布时间:2026/10/10 5:28:36
@pierre/trees 文件树交互配置指南:搜索、重命名、拖拽与 Git 状态实战
【免费下载链接】pierrepierre’s open source code项目地址https://gitcode.com/gh_mirrors/pi/pierre点击查看免费下载pierre/trees是 pierre 仓库中一个以路径字符串为核心的文件树组件库入口在 packages/trees/src/index.ts它把树的模型展开/折叠、选择、搜索、重命名、拖拽、Git 状态与渲染层分离底层由pierre/path-store提供数据结构支撑。本文基于官方 Recipe 文档 recipe-interactions.md 展开系统讲解如何为文件树开启搜索、重命名、拖拽与 Git 状态四类交互并深入源码说明每个配置项的回调时机、校验规则与底层实现。读完本文你将能直接照抄配置模板接入自己的应用并理解这些交互在 FileTreeController 内部是如何被驱动与约束的。安装与入口选择在动手配置交互之前先安装包并选择合适的入口pnpm add pierre/trees如果应用使用 React 渲染层还需安装react与react-dom。pierre/trees提供多套入口详见 SKILL.md入口用途pierre/trees核心 APIFileTree类、控制器、工具函数pierre/trees/reactReact 组件封装pierre/trees/ssr服务端预渲染pierre/trees/web-componentsWeb Components 封装本文聚焦核心 APIFileTree类同时实现了FileTreeMutationHandle与FileTreeSearchSessionHandle两个公共接口因此搜索、重命名、拖拽、Git 状态的所有方法都可以直接在树实例上调用。交互配置总览按需启用一次到位Recipe 的核心思想是「只启用产品实际暴露的交互」。下面这份配置把四类交互全部打开并给出每个回调的落库/落盘位置const tree new FileTree({ paths, search: true, renaming: { onRename(event) { renamePath(event.sourcePath, event.destinationPath); }, }, dragAndDrop: { canDrop({ target }) { return target.kind directory; }, onDropComplete(event) { saveMove(event); }, }, gitStatus, });对照源码可以看出这份配置中search、renaming、dragAndDrop、gitStatus分别落入两条不同的处理路径控制器层search、renaming、dragAndDrop会进入 FileTreeController 的构造函数被解析为#searchMode、#renameEnabled/#onRename、#dragAndDropConfig等私有状态渲染层search、gitStatus会被 FileTree 类 提取出来gitStatus经resolveFileTreeGitStatusState()预处理成按路径索引的状态 Mapsearch则决定是否渲染搜索输入框。搜索search: true与命令式打开在构造选项中传入search: true即可启用内嵌搜索输入框对应FileTree构造器中this.#searchEnabled search true见 render/FileTree.ts。如果搜索框不是常驻 UI而是由应用命令如快捷键、工具栏按钮触发则调用实例方法openSearch()// 从应用命令打开搜索并预填初始关键字 tree.openSearch(TODO);FileTreeSearchSessionHandle接口定义于 model/publicTypes.ts提供了完整的搜索会话控制方法方法作用openSearch(initialValue?)打开搜索会话可带初始关键字closeSearch()关闭搜索会话并清除过滤setSearch(value)直接设置/清空搜索词null表示关闭getSearchValue()读取当前搜索词isSearchOpen()查询搜索会话是否处于打开状态getSearchMatchingPaths()获取当前命中的路径列表focusNextSearchMatch()/focusPreviousSearchMatch()在命中结果间移动焦点搜索模式三种过滤策略树在搜索时的呈现策略由fileTreeSearchMode选项控制类型定义见 model/publicTypes.ts默认值是hide-non-matches模式行为expand-matches展开所有命中路径的祖先目录让结果可见collapse-non-matches保留树结构但折叠不含命中的目录hide-non-matches隐藏不匹配的行默认从实现看搜索时会建立匹配路径集合、可见路径集合等多组索引并把用户手动折叠的目录记录为「折叠覆盖项」#searchCollapsedOverrides使搜索状态与用户的显式操作互不干扰见 FileTreeController.ts。搜索词不区分大小写控制器会缓存小写化后的路径列表以避免每次击键都重新归一化见 FileTreeController.ts。失焦行为与初始搜索searchBlurBehaviorclose默认在输入框失焦时立即清空并关闭搜索会话retain保留当前查询与会话直到显式关闭。retain适合挂在initialSearchQuery上的树——并发兄弟组件抢占焦点时过滤效果依然存活类型注释见 model/publicTypes.ts。initialSearchQuery构造时直接注入初始搜索词。onSearchChange搜索词变化回调可用于同步外部状态。重命名renaming配置与startRenaming()配置与事件回调renaming: { canRename(item) { // 可选控制哪些条目允许重命名 return !item.isFolder; // 例如只允许文件 }, onRename(event) { // 重命名提交后回调必须由应用落库 renamePath(event.sourcePath, event.destinationPath); }, onError(error) { // 可选校验失败回调 showToast(error); }, },canRename({ isFolder, path })返回false则该项不可进入重命名态。onRename(event)提交重命名后触发event为FileTreeRenameEvent包含sourcePath、destinationPath、isFolder三个字段类型见 model/publicTypes.ts。注意树只负责计算新路径真正的持久化改磁盘、改仓库由你在回调里完成。onError(error)名称校验失败时回调错误信息由底层生成。从菜单启动重命名renaming: true只是允许重命名要真正进入重命名态还需要调用startRenaming()// 从右键菜单/上下文菜单启动重命名不传参时重命名当前聚焦项 tree.startRenaming(src/components/Button.tsx);startRenaming()返回布尔值表示是否成功进入重命名态未启用重命名、路径不存在、canRename拒绝都会返回false。从源码看FileTreeController.ts启动重命名时控制器会将路径解析为规范化路径并构造公开重命名路径自动展开所有折叠的祖先目录——否则重命名行永远无法挂载渲染源码注释明确指出这能避免 React 重命名交接效果死循环旋转选中该条目并关闭正在进行的搜索会话以「叶子名称」预填重命名输入框聚焦后进入内联编辑。startRenaming(path, { removeIfCanceled: true })还支持「新建占位条目直接重命名、取消则删除」的流程——取消时若removeIfCanceled为真会以递归方式移除对应条目目录按recursive: true删除见 FileTreeController.ts。内置校验规则重命名路径计算由 renameFileTreePaths.ts 完成它内置了这些校验出错时通过onError通知名称不能为空名称不能包含/目标路径已存在含目录重命名时目标前缀被占用会报错未找到要重命名的条目会报错。重命名语义是「同父目录改名」same-parent basename rename目录重命名会递归重写其下所有子路径若新旧名称相同则视为无操作。控制器在回调onRename之后还会调用move()让内部 store 同步更新见 FileTreeController.ts。拖拽dragAndDrop配置与多选归一化配置项dragAndDrop: { canDrag(paths) { // 可选决定这组路径能否开始拖拽 return paths.length 0; }, canDrop({ target }) { // 目标校验只允许拖到目录上 return target.kind directory; }, onDropComplete(event) { // 落位成功回调应用在此持久化移动 saveMove(event); }, onDropError(error, event) { // 可选落位失败回调 handleDropError(error); }, openOnDropDelay, // 可选悬停目录自动展开的延迟毫秒 },回调签名由FileTreeDragAndDropConfig定义见 model/publicTypes.tscanDrop(event)接收FileTreeDropContext{ draggedPaths, target }target为FileTreeDropTarget{ kind: directory | root, directoryPath, flattenedSegmentPath, hoveredPath }。kind: root表示拖到树根空白处directory表示拖到某个目录行上onDropComplete(event)接收FileTreeDropResult{ draggedPaths, target, operation }其中operation为move单个条目或batch多条目批量移动。多选拖拽的路径归一化多选时同时拖动「文件夹和它的子孙」会造成重复移动。控制器通过normalizeDraggedPaths()去重按路径长度排序后只保留那些没有被选中祖先覆盖的最外层路径保证每个子树恰好移动一次实现见 model/dragAndDrop.ts。落位前的三重防线拖拽从startDrag()到completeDrag()会经过层层校验见 FileTreeController.ts自拖/拖入自身子孙检查isSelfOrDescendantDrop()会拒绝把目录拖进它自己或它的后代dragAndDrop.tscanDrop业务校验返回false即拒绝该目标批量预校验多条目落位前先在一次性临时 store 上演练一遍batch操作避免中途冲突导致已部分写入见 FileTreeController.ts。落位成功后单条目走store.move(from, to)多条目走store.batch(operations)目标为目录时to: dir/被 PathStore 解释为「按源文件 basename 移入该目录」因此拖拽层完全基于路径工作无需自行拼接目标叶子路径注释见 dragAndDrop.ts。最后回调onDropComplete由应用决定是否持久化。Git 状态gitStatus、setGitStatus()与applyGitStatusPatch()初始化传入gitStatus选项接收一组GitStatusEntry每个条目包含路径与状态值用于在树上渲染改动/忽略等装饰。例如const tree new FileTree({ paths, gitStatus: [ { path: src/App.tsx, status: modified }, { path: src/new/Module.ts, status: added }, { path: node_modules/, status: ignored }, ], });底层 model/gitStatus.ts 会把条目解析为规范化路径并构建三组派生数据按路径索引的状态 Map、包含改动的目录集合、被忽略的目录集合同时为每个目录维护「子孙改动计数」changeCountByDirectoryPath供目录行展示汇总徽标。若传入空数组签名0则整个 Git 状态置空。仓库状态变化后同步Recipe 给出的两条命令式更新路径分别对应「整体替换」与「增量补丁」两种场景// 场景一仓库状态大幅变化整体替换 tree.setGitStatus(nextGitStatus); // 场景二增量更新只描述新增/移除的条目 tree.applyGitStatusPatch({ set: [{ path: src/new.ts, status: added }], remove: [src/old.ts], });setGitStatus(entries)整体重建状态render/FileTree.tsapplyGitStatusPatch(patch)增量应用{ set?, remove? }补丁gitStatus.ts。remove里的路径会连带递减其祖先目录的改动计数某个目录计数归零后自动从「有改动目录」集合移除保证徽标始终准确。两条路径都会在状态签名变化时触发就地重渲染通过签名比对相同状态可以跳过无谓渲染getGitStatusSignature/getGitStatusStateSignature。路径约定目录带尾斜杠文件不带Recipe 最后强调的路径约定是整个组件库的公共契约FileTreePublicId即字符串路径目录输入路径以/结尾文件输入路径不以/结尾。// 目录路径 —— 必须以 / 结尾 docs/ src/components/ // 文件路径 —— 不以 / 结尾 src/index.ts README.md这条约定贯穿所有交互的判定逻辑重命名时isCanonicalDirectoryPath(path)直接靠path.endsWith(/)区分目录与文件renameFileTreePaths.ts拖拽的「自拖检查」同样依赖尾斜杠判定目录dragAndDrop.tsGit 状态条目的路径归一化normalizeInputPath也会把目录补上尾斜杠后再进入状态索引gitStatus.ts搜索的祖先展开、选择的范围计算、可见行投影等都以规范化后的路径为准。同时路径字符串是树的公共标识getItem(path)、focusPath(path)、scrollToPath(path)、move(from, to)等所有公开 API 都接受这种格式getItem也兼容src这种不带尾斜杠的目录查询写法见 FileTreeController.ts。与模型无关的交互关注点分离值得强调的是以上所有交互的状态都沉淀在 FileTreeController 中而渲染层React / vanilla / SSR / Web Components只是消费它的快照。这意味着你可以在不挂载任何 UI 的情况下用控制器跑通「搜索 → 重命名 → 移动」的完整流程树实例暴露的add/remove/move/batch/resetPaths等变异方法与onMutation事件类型见 model/publicTypes.ts是外部数据源同步树内容的官方通道subscribe(listener)让任意渲染层都能以「订阅快照」的方式响应交互引起的状态变化。更多阅读分场景 RecipeReact 渲染、vanilla JS 渲染、SSR 预渲染、主题应用API 参考Core API、React API、SSR API、Web Components API源码探索FileTreeController、交互相关类型定义、拖拽实现、Git 状态实现、重命名路径计算赞分享【免费下载链接】pierrepierre’s open source code项目地址https://gitcode.com/gh_mirrors/pi/pierre点击查看免费下载相关推荐pierre/trees 文件树组件全指南安装、API 选型、React/SSR/Web Components 接入与交互配置pierre/trees 文件树组件全指南安装、API 选型、React/SSR/Web Components 接入与交互配置 pierre/trees在 React 中使用 pierre/trees 渲染与更新文件树完整实战指南在 React 中使用 pierre/trees 渲染与更新文件树完整实战指南 本篇技术指南围绕 pierre/trees 的 React 集成方式展开pierre/trees 文件树组件实战指南path-first 设计、SSR 预渲染与主题定制pierre/trees 文件树组件实战指南path first 设计、SSR 预渲染与主题定制 pierre/trees 是 pierre 仓库中一个以上一篇Yuedu项目依赖锁定与浮动版本策略选择下一篇Electron桌面应用动画效果CSS与JavaScript的完美结合创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考