Skip to content

Commit 6efea55

Browse files
committed
2 parents 8f81d0b + eff2eab commit 6efea55

5 files changed

Lines changed: 113 additions & 16 deletions

File tree

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

packages/doc-docs/关于训练营/王梓绵答辩.md

Lines changed: 113 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -300,27 +300,124 @@ const items = [
300300
*图:构建总结流程图*
301301
302302
#### 1. 我们当前的设计是将文件夹树的构建和文档的分配分离,具体来说:
303-
后端只负责构建文件夹的树形结构(通过递归查询文件夹表),前端在拿到文件夹树和文档列表(可能是单独请求的)后,通过`buildFolderDocumentTree`方法将文档分配到对应的文件夹节点(包括根节点) 而另一种常见的做法是:在后端构建树的时候同时查询文档,将文档作为叶子节点直接构建到树中。
303+
后端只负责构建文件夹的树形结构(通过递归查询文件夹表),前端在拿到文件夹树和文档列表(单独请求的)后,通过`buildFolderDocumentTree`方法将文档分配到对应的文件夹节点(包括根节点) 而另一种常见的做法是:在后端构建树的时候同时查询文档,将文档作为叶子节点直接构建到树中。
304304
#### 2. 当前设计的好处:
305-
1. 职责分离,结构清晰:
305+
1. *职责分离,结构清晰*
306306
- 文件夹树和文档属于不同的数据类型,分开处理使得逻辑更清晰。
307-
- 文件夹树的结构相对稳定(嵌套关系),而文档可能频繁变动(如重命名、移动、删除)。将文档处理放在前端,可以避免每次文件夹结构变动都要重新构建整个树(包括文档)。
308-
2. 减少后端计算压力:
307+
- 将文档处理放在前端,可以避免每次文档结构变动都要重新构建整个树(包括文档)。
308+
2. *减少后端计算压力*
309309
- 如果一起构建,后端需要同时处理文件夹和文档的递归,尤其是在文档数量很大的情况下,构建整个树的开销会很大。
310310
- 当前设计下,后端只处理文件夹(通常数量远少于文档),文档的处理放在前端,利用浏览器的计算能力。
311-
3. 灵活性:
312-
- 前端可以独立获取文档列表(例如分页、按条件过滤),然后根据需求动态地分配到文件夹树中。如果文档列表需要更新(比如用户搜索),我们只需要重新运行`buildFolderDocumentTree`方法,而不需要重新请求整个文件夹树。
311+
3. *灵活性*
312+
- 前端可以独立获取文档列表(例如按条件过滤),然后根据需求动态地分配到文件夹树中。如果文档列表需要更新(比如用户搜索),我们只需要重新运行`buildFolderDocumentTree`方法,而不需要重新请求整个文件夹树。
313313
- 如果文档和文件夹树一起构建,那么每次文档更新(比如新增一个文档)都需要重新构建整个树并返回,这在文档数量大时效率低下。
314-
4. 减少数据传输量:
315-
- 假设一个场景:用户只是展开了一个文件夹,需要加载该文件夹下的文档。如果采用分离的方式,我们可以只请求该文件夹下的文档,然后动态添加到已有的树中。而如果一开始就把所有文档都构建在树中,那么初始加载的数据量会非常大。
316-
5. 支持懒加载:
317-
- 当前设计可以轻松实现文档的懒加载。例如,一开始只加载文件夹树,当用户展开某个文件夹时,再去请求该文件夹下的文档。这样可以显著提高初始加载速度。
318-
6. 处理根级文档更灵活:
319-
- 根级文档(没有父文件夹)在当前的分离设计中,可以通过一个特殊的`ROOT`键来存放,这样在展示时,前端可以自由决定如何展示根级文档(比如在文件夹树的最上方或最下方单独展示)。
320-
7. 避免重复数据:
321-
- 在树形结构中,每个节点(文件夹或文档)都需要独立表示。如果文档数量庞大,那么构建的树会非常大。而分离处理允许我们只传输一次文档列表,然后在多个地方引用(例如,在文件夹树中引用文档,在最近文档列表中也可以引用同一份文档数据)。
322-
8. 更新效率:
323-
- 当文档发生变化(如移动)时,我们只需要更新文档的`parentFolderIds`,然后在前端重新运行`buildFolderDocumentTree`即可,不需要重新构建整个文件夹树。
314+
4. *支持文档懒加载*:
315+
- 当前设计可以轻松实现文档的懒加载。例如,一开始只加载文件夹树,当用户展开某个文件夹时,再去请求该文件夹下的文档,然后动态添加到已有的树中。这样可以显著提高初始加载速度。而如果一开始就把所有文档都构建在树中,那么初始加载的数据量会非常大。
316+
317+
#### 1.3 生成唯一默认文件名/文件夹名
318+
319+
320+
##### 1.3.1 逻辑步骤
321+
**(1) 收集现有名称**:
322+
323+
- 创建一个 Set 集合 existingNames 存储所有不可重复的名称。
324+
325+
- 添加额外名称:遍历 additionalNames 参数,将非空名称添加到集合中。
326+
327+
- 递归查找目标文件夹
328+
329+
- 处理根目录:若 targetKey === 'root',直接查找根节点(key='root')的子项名称。
330+
331+
**(2) 生成唯一名称**:
332+
333+
- 初始化计数器 counter = 1,生成候选名称 candidateName = baseName + counter。
334+
335+
- 循环检查:若 candidateName 在 existingNames 中存在,则 counter++ 并生成新名称。
336+
337+
- 返回结果:直到找到不在集合中的名称,返回最终的 candidateName。
338+
339+
##### 1.3.2 关键代码:
340+
```javascript
341+
/**
342+
* 生成唯一的默认文件名/文件夹名,避免同级目录下的重复
343+
* @param {string} baseName - 基础名称,如"新建文档"或"新建文件夹"
344+
* @param {string} targetKey - 目标文件夹的key
345+
* @param {Array} additionalNames - 额外需要检查的名称列表(如后端最新数据)
346+
* @returns {string} 唯一的名称
347+
*/
348+
const generateUniqueDefaultName = (
349+
baseName,
350+
targetKey,
351+
additionalNames = [],
352+
) => {
353+
// 获取目标文件夹的现有子项
354+
const getExistingNames = () => {
355+
const existingNames = new Set();
356+
357+
// 添加额外的名称列表(来自后端的最新数据)
358+
additionalNames.forEach(name => {
359+
if (name) existingNames.add(name);
360+
});
361+
362+
// 递归查找目标文件夹及其子项
363+
const findTargetFolderItems = (nodes, key) => {
364+
for (const node of nodes) {
365+
if (node.key === key) {
366+
// 找到目标文件夹,收集其子项名称
367+
if (node.children) {
368+
node.children.forEach(child => {
369+
const name = child.label?.props?.text || child.label;
370+
if (name) {
371+
existingNames.add(name);
372+
}
373+
});
374+
}
375+
return true;
376+
}
377+
if (node.children) {
378+
if (findTargetFolderItems(node.children, key)) {
379+
return true;
380+
}
381+
}
382+
}
383+
return false;
384+
};
385+
386+
// 如果是根目录
387+
if (targetKey === 'root') {
388+
const rootFolder = folderList.find(item => item.key === 'root');
389+
if (rootFolder && rootFolder.children) {
390+
rootFolder.children.forEach(child => {
391+
const name = child.label?.props?.text || child.label;
392+
if (name) {
393+
existingNames.add(name);
394+
}
395+
});
396+
}
397+
} else {
398+
findTargetFolderItems(folderList, targetKey);
399+
}
400+
401+
return existingNames;
402+
};
403+
404+
const existingNames = getExistingNames();
405+
406+
console.log('现有名称集合:', [...existingNames]);
407+
408+
// 从1开始尝试生成唯一名称
409+
let counter = 1;
410+
let candidateName = `${baseName}${counter}`;
411+
412+
while (existingNames.has(candidateName)) {
413+
counter++;
414+
candidateName = `${baseName}${counter}`;
415+
}
416+
417+
console.log('生成的唯一名称:', candidateName);
418+
return candidateName;
419+
};
420+
```
324421
325422
## 2. slate中编辑器代码块高亮
326423
![image-20250708021052107](./image/image-20250708021052107.png)

0 commit comments

Comments
 (0)