mcpField
S
syncfusion-javascript-file-manager

syncfusion-javascript-file-manager

github.com/syncfusion开发063 次安装1 周前更新
代码仓库

关于 syncfusion-javascript-file-manager

为使用 Syncfusion FileManager 的开发者提供 TypeScript 实现参考,涵盖文件浏览器和文档管理界面的配置与集成。内容从常见文件操作延伸到自定义文件系统提供程序、权限控制和大型列表优化。

主要功能

  1. 01TypeScript 组件初始化与配置
  2. 02上传、下载及文件操作
  3. 03工具栏、菜单和视图定制
  4. 04自定义文件系统提供程序
  5. 05本地化与 RTL 渲染
  6. 06权限控制和列表虚拟化

适用场景

  1. 01构建文件浏览或文档管理界面
  2. 02配置文件上传验证与目录上传
  3. 03为文件列表添加搜索和自定义排序
  4. 04接入自定义文件系统提供程序

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/syncfusion/javascript-ui-controls-skills --skill syncfusion-javascript-file-manager

安装后在 Claude Code 中输入/syncfusion-javascript-file-manager确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
advanced-configuration.md
advanced-features.md
customization.md
data-binding.md
docker-deployment.md
file-operations.md
file-system-providers-detailed.md
getting-started.md
localization-and-internationalization.md
navigation-and-views.md
styling-and-ui.md

详细介绍

实现 Syncfusion TypeScript FileManager - 完整参考

Syncfusion FileManager 组件是一款企业级 Web 文件管理系统,用于浏览、管理和整理文件及文件夹。它提供全面的文件操作、自定义选项和高级功能,包括拖放、虚拟化、多语言支持、RTL 渲染和基于角色的访问控制。

目录

  1. 何时使用此技能
  2. 快速开始
  3. 完整导航指南
  4. 核心属性参考
  5. 配置对象
  6. 方法参考
  7. 事件参考
  8. UI 模块与注入
  9. 常见模式和场景
  10. 高级集成
  11. 最佳实践
  12. API 兼容性矩阵

何时使用此技能

适用场景:

  • 创建企业级文件浏览器或文档管理界面
  • 实现具备验证功能的完整文件上传/下载功能
  • 针对特定工作流自定义工具栏、上下文菜单和视图
  • 构建支持范围选择的多选文件选择界面
  • 实现带自定义验证的高级拖放文件处理
  • 集成自定义文件系统提供程序(Physical、Azure、S3 等)
  • 应用本地化、RTL 支持和多语言界面
  • 实现访问控制和基于角色的权限
  • 使用虚拟化优化大型文件列表
  • 执行自定义排序、筛选和搜索
  • 构建文件的嵌套或扁平数据结构
  • 跨会话持久化组件状态
  • 自定义缩略图和文件预览
  • 构建目录上传功能

快速开始

最小配置
import { FileManager, Toolbar, NavigationPane, DetailsView } from '@syncfusion/ej2-filemanager';

// Step 1: Inject required modules
FileManager.Inject(Toolbar, NavigationPane, DetailsView);

// Step 2: Initialize FileManager with AJAX configuration
const filemanager = new FileManager({
    ajaxSettings: {
        url: 'https://your-api.com/api/FileManager/FileOperations',
        getImageUrl: 'https://your-api.com/api/FileManager/GetImage',
        uploadUrl: 'https://your-api.com/api/FileManager/Upload',
        downloadUrl: 'https://your-api.com/api/FileManager/Download'
    },
    height: '100%',
    width: '100%'
});

// Step 3: Render to DOM element
filemanager.appendTo('#filemanager');
HTML 模板

首先,安装 Fluent 2 主题包:

npm install @syncfusion/ej2-fluent2-theme --save

然后在 index.css 文件中引用主题 CSS(FileManager 的 index.css 会自动加载所有必需的依赖样式):

@import "../node_modules/@syncfusion/ej2-fluent2-theme/styles/file-manager/index.css";

然后创建一个基本的 HTML 容器:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Syncfusion FileManager</title>
    <link href="index.css" rel="stylesheet" />
</head>
<body>
    <div id="filemanager"></div>
    <script src="index.js"></script>
</body>
</html>

完整导航指南

入门与基础知识

📄 阅读: references/getting-started.md

  • 主题: 安装、配置、CSS 导入、基本初始化、渲染、配置
文件操作与 API 集成

📄 阅读: references/file-operations.md

  • 主题: 上传/下载、CRUD 操作、目录上传、搜索功能

📄 阅读: references/file-operations-detailed.md

  • 主题: 完整的请求/响应参数、全部 11 种操作、错误代码、TypeScript 类型
样式、自定义与 UI

📄 阅读: references/styling-and-ui.md

  • 主题: CSS 自定义、工具栏自定义、上下文菜单、导航窗格模板
视图与导航

📄 阅读: references/navigation-and-views.md

  • 主题: 视图模式(详细信息、大图标)、面包屑、导航窗格、虚拟化
高级功能

📄 阅读: references/advanced-features.md

  • 主题: 拖放、多选、范围选择、本地化、RTL、访问控制
配置与数据绑定

📄 阅读: references/advanced-configuration.md

  • 主题: 自定义提供程序、数据结构(嵌套/扁平)、排序、验证、访问控制

📄 阅读: references/data-binding.md

  • 主题: AJAX 设置、自定义提供程序、服务端通信、请求/响应处理
文件系统提供程序

📄 阅读: references/file-system-providers-detailed.md

  • 主题: 10 种完整的提供程序,包含设置、配置和示例
Docker 部署

📄 阅读: references/docker-deployment.md

  • 主题: 用于 Azure Blob Storage 和 Amazon S3 的统一 syncfusion/filemanager-provider Docker 镜像、环境变量配置、docker-compose.yml 示例、客户端 ajaxSettings、故障排除
本地化

📄 阅读: references/localization-and-internationalization.md

  • 主题: 多语言支持、区域设置、RTL 渲染、自定义翻译

核心属性参考

完整属性列表
属性类型默认值描述
ajaxSettingsAjaxSettingsModel{}与服务器通信的 AJAX 配置
allowDragAndDropbooleanfalse启用拖放操作
allowMultiSelectionbooleantrue启用多文件选择
contextMenuSettingsContextMenuSettingsModel{...}上下文菜单配置
cssClassstring""用于自定义样式的 CSS 类
detailsViewSettingsDetailsViewSettingsModel{...}详细信息视图网格配置
enableHtmlSanitizerbooleantrue清理 HTML 以防止 XSS
enablePersistencebooleanfalse保留视图、路径和选择状态
enableRangeSelectionbooleanfalse启用 Shift+单击范围选择
enableRtlbooleanfalse以 RTL 方向渲染
enableVirtualizationbooleanfalse为大型列表启用虚拟化
fileSystemDataFileData[][]本地文件系统数据数组。每个项目必须包含:dateCreated、dateModified、filterPath、hasChild、id、isFile、name、parentId、size、type
heightstring | number"400px"组件高度
largeIconsTemplatestring | Functionnull大图标视图的自定义模板
localestring"en-US"本地化语言代码
navigationPaneSettingsNavigationPaneSettingsModel{...}导航窗格配置
navigationPaneTemplatestring | Functionnull导航窗格的自定义模板
pathstring"/"要显示的当前文件路径
popupTargetHTMLElement | stringnull对话框弹出目标元素
rootAliasNamestringnull根文件夹显示名称
searchSettingsSearchSettingsModel{...}搜索配置
selectedItemsstring[][]预先选中的文件/文件夹
showFileExtensionbooleantrue在列表中显示文件扩展名
showHiddenItemsbooleanfalse在列表中包含隐藏文件
showItemCheckBoxesbooleantrue悬停时显示复选框
showThumbnailbooleantrue显示文件缩略图
sortBystring"name"排序字段名称
sortComparerSortComparer | stringnull自定义排序函数
sortOrderSortOrder"Ascending"排序方向(Ascending、Descending、None)
toolbarItemsToolbarItemModel[][]自定义工具栏项目数组
toolbarSettingsToolbarSettingsModel{...}工具栏配置
uploadSettingsUploadSettingsModel{...}文件上传配置
viewViewType"LargeIcons"初始视图类型(LargeIcons 或 Details)
widthstring | number"100%"组件宽度
属性示例
// Example 1: Basic configuration
const filemanager = new FileManager({
    path: '/Documents',
    view: 'Details',
    height: '500px',
    width: '100%',
    allowMultiSelection: true,
    showThumbnail: true
});

// Example 2: Persistence and RTL
const filemanager = new FileManager({
    enablePersistence: true,  // Saves view, path, selection
    enableRtl: true,
    locale: 'ar-AE',
    cssClass: 'custom-fm-theme'
});

// Example 3: Range selection and drag-drop
const filemanager = new FileManager({
    allowDragAndDrop: true,
    enableRangeSelection: true,
    allowMultiSelection: true,
    enableHtmlSanitizer: true
});

配置对象

1. AjaxSettings

配置文件操作的服务器端点。

属性类型描述
urlstring文件操作(读取、创建、删除等)的服务器端点
uploadUrlstring文件上传的服务器端点
downloadUrlstring文件下载的服务器端点
getImageUrlstring获取图像/缩略图的服务器端点
const filemanager = new FileManager({
    ajaxSettings: {
        url: 'https://api.example.com/api/FileManager/FileOperations',
        uploadUrl: 'https://api.example.com/api/FileManager/Upload',
        downloadUrl: 'https://api.example.com/api/FileManager/Download',
        getImageUrl: 'https://api.example.com/api/FileManager/GetImage'
    }
});
2. UploadSettings

控制文件上传行为和验证。

属性类型默认值描述
allowedExtensionsstring""允许的文件扩展名(以逗号分隔,例如 ".jpg,.png,.pdf")
autoClosebooleanfalse上传所有文件后关闭上传对话框
autoUploadbooleantrue选择文件后自动上传
chunkSizenumber0将大文件拆分为分块(字节)并依次上传
directoryUploadbooleanfalse允许上传文件夹/目录
maxFileSizenumber30000000最大文件大小(字节,默认值:30MB)
minFileSizenumber0最小文件大小(字节)
sequentialUploadbooleanfalse一次上传一个文件,依次进行
const filemanager = new FileManager({
    uploadSettings: {
        allowedExtensions: '.jpg,.png,.pdf,.docx',  // Comma-separated extensions
        maxFileSize: 52428800,                      // 50 MB
        minFileSize: 1024,                          // 1 KB
        autoUpload: true,                           // Auto-upload on selection
        autoClose: false,                           // Keep dialog open after upload
        directoryUpload: true,                      // Allow folder upload
        sequentialUpload: false,                    // Upload multiple files at once
        chunkSize: 0                                // No chunking (0 = disabled)
    }
});
3. ToolbarSettings

自定义工具栏及可用操作。

属性类型描述
itemsToolBarItems[]工具栏项目数组
visibleboolean显示/隐藏工具栏
const filemanager = new FileManager({
    toolbarSettings: {
        items: [
            'NewFolder', 'Refresh', 'Upload', 'Delete', 'Download', 
            'Rename', 'SortBy', 'View', 'Details'
        ],
        visible: true
    }
});
4. ContextMenuSettings

配置文件、文件夹和布局的上下文菜单项目。

属性类型描述
filestring[]文件菜单项目
folderstring[]文件夹菜单项目
layoutstring[]空白区域菜单项目
visibleboolean显示/隐藏上下文菜单
const filemanager = new FileManager({
    contextMenuSettings: {
        file: ['Open', 'Cut', 'Copy', 'Delete', 'Rename', 'Details'],
        folder: ['Open', 'Cut', 'Copy', 'Paste', 'Delete', 'Rename'],
        layout: ['Refresh', 'NewFolder', 'Paste', 'SortBy', 'View'],
        visible: true
    }
});
5. NavigationPaneSettings

自定义左侧导航窗格。

属性类型默认值描述
visiblebooleantrue显示/隐藏导航窗格
maxWidthstring"200px"导航窗格的最大宽度
minWidthstring"150px"导航窗格的最小宽度
const filemanager = new FileManager({
    navigationPaneSettings: {
        visible: true,
        maxWidth: '300px',
        minWidth: '200px'
    }
});
6. DetailsViewSettings

配置详细信息视图中的网格显示。

属性类型描述
columnsColumn[]网格的列定义
hideColumnsstring[]隐藏指定列
const filemanager = new FileManager({
    detailsViewSettings: {
        columns: [
            { field: 'name', headerText: 'File Name', width: '200px' },
            { field: 'dateModified', headerText: 'Date Modified', width: '150px' },
            { field: 'type', headerText: 'Type', width: '100px' },
            { field: 'size', headerText: 'Size', width: '100px' }
        ]
    }
});
7. SearchSettings

配置搜索功能。

属性类型默认值描述
filterTypeFilterType"StartsWith"搜索匹配方式:"StartsWith"、"Contains"、"EndsWith"
ignoreCasebooleantrue搜索时忽略大小写
const filemanager = new FileManager({
    searchSettings: {
        filterType: 'Contains',
        ignoreCase: true
    }
});

方法参考

完整方法列表 - 共 27+ 个方法
文件操作方法
方法签名返回值描述
openFile(id: string) => voidvoid按 ID 打开文件或文件夹
deleteFiles(ids?: string[]) => voidvoid按 ID 或所选项目删除文件/文件夹
renameFile(id?: string, name?: string) => voidvoid重命名文件或文件夹
createFolder(name?: string) => voidvoid创建新文件夹
downloadFiles(ids?: string[]) => voidvoid下载文件或所选项目
uploadFiles() => voidvoid打开上传对话框
refreshFiles() => voidvoid刷新当前目录列表
filterFiles(filterData?: Object) => voidvoid显示自定义筛选后的文件
选择方法
方法签名返回值描述
selectAll() => voidvoid选中当前路径中的所有文件和文件夹
clearSelection() => voidvoid取消选中所有已选中的文件和文件夹
getSelectedFiles() => Object[]Object[]获取当前选中文件的详细信息
导航和视图方法
方法签名返回值描述
traverseBackward() => voidvoid向后导航(父目录)
refresh() => voidvoid刷新并重新渲染整个组件
refreshLayout() => voidvoid仅刷新布局
工具栏和菜单管理
方法签名返回值描述
enableToolbarItems(items: string[]) => voidvoid启用指定的工具栏项
disableToolbarItems(items: string[]) => voidvoid禁用指定的工具栏项
getToolbarItemIndex(item: string) => numbernumber获取工具栏项的索引
enableMenuItems(items: string[]) => voidvoid启用指定的上下文菜单项
disableMenuItems(items: string[]) => voidvoid禁用指定的上下文菜单项
getMenuItemIndex(item: string) => numbernumber获取菜单项的索引
对话框管理
方法签名返回值描述
closeDialog() => voidvoid以编程方式关闭已打开的对话框
组件生命周期
方法签名返回值描述
appendTo(selector?: string | HTMLElement) => voidvoid将组件附加到 DOM
destroy() => voidvoid销毁组件
dataBind() => voidvoid立即应用待处理的属性更改
getRootElement() => HTMLElementHTMLElement返回根 DOM 元素
事件管理
方法签名返回值描述
addEventListener(eventName: string, handler: Function) => voidvoid添加事件监听器
removeEventListener(eventName: string, handler: Function) => voidvoid移除事件监听器
模块注入
方法签名返回值描述
Inject(moduleList: Function[]) => voidvoid动态注入所需模块
方法使用示例
// File Operations
filemanager.openFile('file-id-123');
filemanager.deleteFiles(['file1.txt', 'folder/file2.pdf']);
filemanager.renameFile('file.txt', 'renamed-file.txt');
filemanager.createFolder('New Folder');
filemanager.downloadFiles(['doc1.pdf', 'doc2.docx']);
filemanager.uploadFiles();
filemanager.refreshFiles();
filemanager.filterFiles({ action: 'customFilter', data: {...} });

// Selection Management
filemanager.selectAll();
filemanager.clearSelection();
const selected = filemanager.getSelectedFiles();
console.log(selected);  // Array of FileData objects

// Navigation
filemanager.traverseBackward();
filemanager.refresh();
filemanager.refreshLayout();

// Toolbar Control
filemanager.enableToolbarItems(['NewFolder', 'Upload', 'Delete']);
filemanager.disableToolbarItems(['Cut', 'Copy']);
const toolbarIndex = filemanager.getToolbarItemIndex('Download');

// Menu Control
filemanager.enableMenuItems(['Open', 'Delete']);
filemanager.disableMenuItems(['Rename']);
const menuIndex = filemanager.getMenuItemIndex('Details');

// Dialogs
filemanager.closeDialog();

// Module Injection
import { FileManager, Toolbar, NavigationPane, DetailsView } from '@syncfusion/ej2-filemanager';
FileManager.Inject(Toolbar, NavigationPane, DetailsView);

// Event Handling
filemanager.addEventListener('fileSelect', (args) => {
    console.log('File selected:', args);
});
filemanager.removeEventListener('fileSelect', handler);
view: 'Details'

});

// Component refresh filemanager.refresh();


---

## Events Reference

### Complete Events List - All 37 Events

#### Lifecycle Events

| Event | EventArgs | Trigger | Description |
|-------|-----------|---------|-------------|
| `created` | Object | Component initialized | Fires when FileManager component is created |
| `destroyed` | Object | Component destroyed | Fires when FileManager component is destroyed |

#### AJAX/Server Communication Events

| Event | EventArgs | Trigger | Description |
|-------|-----------|---------|-------------|
| `beforeSend` | BeforeSendEventArgs | Before server request | Fires before AJAX request to server |
| `success` | SuccessEventArgs | After successful operation | Fires when AJAX request succeeds |
| `failure` | FailureEventArgs | After failed operation | Fires when AJAX request fails |

#### File Selection Events

| Event | EventArgs | Trigger | Description |
|-------|-----------|---------|-------------|
| `fileSelect` | FileSelectEventArgs | File selected/unselected | Fires when file is selected or unselected |
| `fileSelection` | FileSelectionEventArgs | Before file selected | Fires before file is selected |

#### File Operation Events (Before)

| Event | EventArgs | Trigger | Description |
|-------|-----------|---------|-------------|
| `beforeDelete` | DeleteEventArgs | Before delete operation | Fires before file/folder deletion |
| `beforeRename` | RenameEventArgs | Before rename operation | Fires before file/folder rename |
| `beforeFolderCreate` | FolderCreateEventArgs | Before folder creation | Fires before new folder creation |
| `beforeMove` | MoveEventArgs | Before move/paste operation | Fires when file begins to move |
| `beforeDownload` | BeforeDownloadEventArgs | Before download request | Fires before sending download request |
| `beforeImageLoad` | BeforeImageLoadEventArgs | Before image retrieval | Fires before getting image/thumbnail |

#### File Operation Events (After)

| Event | EventArgs | Trigger | Description |
|-------|-----------|---------|-------------|
| `delete` | DeleteEventArgs | After deletion | Fires after successful file/folder deletion |
| `rename` | RenameEventArgs | After rename complete | Fires when file/folder is renamed |
| `folderCreate` | FolderCreateEventArgs | After folder created | Fires when new folder is created |
| `move` | MoveEventArgs | After paste operation | Fires when file/folder is pasted |

#### File Access Events

| Event | EventArgs | Trigger | Description |
|-------|-----------|---------|-------------|
| `fileLoad` | FileLoadEventArgs | Before file rendered | Fires before file/folder is rendered |
| `fileOpen` | FileOpenEventArgs | Before file opened | Fires before file/folder is opened |

#### Drag and Drop Events

| Event | EventArgs | Trigger | Description |
|-------|-----------|---------|-------------|
| `fileDragStart` | FileDragEventArgs | Drag starts | Fires when file/folder dragging starts |
| `fileDragging` | FileDragEventArgs | While dragging | Fires while dragging file/folder |
| `fileDragStop` | FileDragEventArgs | Before drop | Fires when file about to be dropped |
| `fileDropped` | FileDragEventArgs | After drop | Fires when file/folder is dropped |

#### UI Interaction Events

| Event | EventArgs | Trigger | Description |
|-------|-----------|---------|-------------|
| `menuOpen` | MenuOpenEventArgs | Before menu opens | Fires before context menu opens |
| `menuClick` | MenuClickEventArgs | Menu item clicked | Fires when context menu item clicked |
| `menuClose` | MenuCloseEventArgs | Before menu closes | Fires before context menu closes |
| `toolbarCreate` | ToolbarCreateEventArgs | Before toolbar rendered | Fires before toolbar is created |
| `toolbarClick` | ToolbarClickEventArgs | Toolbar button clicked | Fires when toolbar item clicked |

#### Dialog Events

| Event | EventArgs | Trigger | Description |
|-------|-----------|---------|-------------|
| `beforePopupOpen` | BeforePopupOpenCloseEventArgs | Before dialog opens | Fires before dialog/popup opens |
| `beforePopupClose` | BeforePopupOpenCloseEventArgs | Before dialog closes | Fires before dialog/popup closes |
| `popupOpen` | PopupOpenCloseEventArgs | After dialog opened | Fires when dialog/popup is opened |
| `popupClose` | PopupOpenCloseEventArgs | After dialog closed | Fires when dialog/popup is closed |

#### Search and Upload Events

| Event | EventArgs | Trigger | Description |
|-------|-----------|---------|-------------|
| `search` | SearchEventArgs | During search | Fires when search is performed |
| `uploadListCreate` | UploadListCreateArgs | Before upload item rendered | Fires before each file in upload dialog |

### Data Structure Interfaces

#### FileData (fileSystemData items)
```typescript
interface FileData {
    dateCreated?: Date;           // File/folder creation date in ISO 8601 format
    dateModified?: Date;          // Last modified date in ISO 8601 format
    filterPath: string;           // Full path from root (e.g., "", "Files/", "Files/Documents/")
    hasChild?: boolean;           // true if folder has subfolders/files, false for files
    id: string;                   // Unique identifier for the file/folder
    isFile: boolean;              // true for files, false for folders
    name: string;                 // File/folder name (display name)
    parentId?: string | null;     // Parent folder ID (null for root items)
    size?: number;                // Size in bytes
    type?: string;                // File extension or type (e.g., "folder", "pdf", "jpg")
    children?: FileData[];        // Child items for nested data structures (optional)
}

// Example Usage:
const fileData: FileData = {
    dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
    dateModified: new Date("2024-01-08T18:16:38.4384894+05:30"),
    filterPath: "",
    hasChild: true,
    id: '0',
    isFile: false,
    name: "Files",
    parentId: null,
    size: 1779448,
    type: "folder"
};
事件参数结构
BeforeSendEventArgs
interface BeforeSendEventArgs {
    action: string;           // AJAX action name
    ajaxSettings: Object;     // AJAX settings sent to server
    cancel: boolean;          // Set to true to cancel
}
FileSelectEventArgs
interface FileSelectEventArgs {
    action: string;           // 'select' or 'unselect'
    fileDetails: Object;      // Selected file/folder data
    isInteracted: boolean;    // True if user-triggered
}
FileSelectionEventArgs
interface FileSelectionEventArgs {
    action: string;           // 'select' or 'unselect'
    fileDetails: Object;      // File/folder being selected
    isInteracted: boolean;    // True if user-triggered
}
DeleteEventArgs
interface DeleteEventArgs {
    cancel: boolean;          // Set to true to cancel deletion
    itemData: Object[];       // Data of deleted items
    path: string;             // Current folder path
}
RenameEventArgs
interface RenameEventArgs {
    cancel: boolean;          // Set to true to cancel rename
    itemData: Object;         // Renamed item data
    newName: string;          // New file/folder name
    oldName: string;          // Original file/folder name
    path: string;             // Current folder path
}
FolderCreateEventArgs
interface FolderCreateEventArgs {
    cancel: boolean;          // Set to true to cancel creation
    itemData: Object;         // Created folder data
    path: string;             // Parent folder path
}
MoveEventArgs
interface MoveEventArgs {
    cancel: boolean;          // Set to true to cancel move
    itemData: Object[];       // Items being moved
    path: string;             // Destination path
    sourceItems: Object[];    // Source item details
}
FileDragEventArgs
interface FileDragEventArgs {
    cancel: boolean;          // Set to true to cancel drag
    element: HTMLElement;     // Drag element
    event: MouseEvent | TouchEvent;  // Native drag event
    fileDetails: Object[];    // Files being dragged
    target: HTMLElement;      // Drop target element
}
FileLoadEventArgs
interface FileLoadEventArgs {
    element: HTMLElement;     // Rendered DOM element
    fileDetails: Object;      // File/folder data
    module: string;           // Module name (DetailsView, LargeIconsView)
}
FileOpenEventArgs
interface FileOpenEventArgs {
    cancel: boolean;          // Set to true to prevent opening
    fileDetails: Object;      // Opened file/folder data
    module: string;           // Module name
}
MenuOpenEventArgs
interface MenuOpenEventArgs {
    cancel: boolean;          // Set to true to cancel menu
    element: HTMLElement;     // Context menu element
    fileDetails: Object;      // Right-clicked file/folder
    items: Object[];          // Menu items to display
}
MenuClickEventArgs
interface MenuClickEventArgs {
    cancel: boolean;          // Set to true to cancel action
    element: HTMLElement;     // Clicked menu item element
    fileDetails: Object;      // Target file/folder
    item: Object;             // Menu item clicked
}
MenuCloseEventArgs
interface MenuCloseEventArgs {
    cancel: boolean;          // Set to true to keep menu open
    element: HTMLElement;     // Context menu element
}
ToolbarCreateEventArgs
interface ToolbarCreateEventArgs {
    cancel: boolean;          // Set to true to cancel creation
    element: HTMLElement;     // Toolbar DOM element
    items: Object[];          // Toolbar items array
}
ToolbarClickEventArgs
interface ToolbarClickEventArgs {
    cancel: boolean;          // Set to true to cancel default action
    item: Object;             // Clicked toolbar item
    element: HTMLElement;     // Clicked toolbar element
}
BeforePopupOpenCloseEventArgs
interface BeforePopupOpenCloseEventArgs {
    cancel: boolean;          // Set to true to cancel
    element: HTMLElement;     // Dialog element
}
PopupOpenCloseEventArgs
interface PopupOpenCloseEventArgs {
    element: HTMLElement;     // Dialog element
    isInteracted: boolean;    // True if user-triggered
}
SearchEventArgs
interface SearchEventArgs {
    cancel: boolean;          // Set to true to cancel search
    searchString: string;     // Search query
}
UploadListCreateArgs
interface UploadListCreateArgs {
    element: HTMLElement;     // Upload item DOM element
    fileData: Object;         // File data
    index: number;            // Item index
    postData: Object;         // Upload POST data
}
SuccessEventArgs
interface SuccessEventArgs {
    action: string;           // Completed action name
    result: any;              // Operation result
}
FailureEventArgs
interface FailureEventArgs {
    action: string;           // Failed action name
    error: string;            // Error message
}
完整事件处理程序示例
示例 1:文件操作与事件处理
const filemanager = new FileManager({
    ajaxSettings: {
        url: 'https://api.example.com/api/FileManager/FileOperations'
    },
    
    // Before any server request
    beforeSend: (args) => {
        console.log('Action:', args.action);
        // Add authentication token
        args.ajaxSettings.headers = { 'Authorization': 'Bearer token' };
    },
    
    // File operations
    beforeDelete: (args) => {
        console.log('Deleting:', args.itemData.map(f => f.name));
        // Confirm or cancel
    },
    
    delete: (args) => {
        console.log('Deleted successfully');
    },
    
    beforeRename: (args) => {
        console.log('Renaming:', args.oldName, '→', args.newName);
    },
    
    rename: (args) => {
        console.log('Rename complete');
    },
    
    beforeFolderCreate: (args) => {
        console.log('Creating folder in:', args.path);
    },
    
    folderCreate: (args) => {
        console.log('Folder created');
    },
    
    beforeMove: (args) => {
        console.log('Moving to:', args.path);
    },
    
    move: (args) => {
        console.log('Move complete');
    }
});
示例 2:选择和访问事件
const filemanager = new FileManager({
    // Selection events
    fileSelection: (args) => {
        console.log('About to select:', args.fileDetails.name);
        // Can set args.cancel = true to prevent
    },
    
    fileSelect: (args) => {
        console.log('Selected:', args.action);
        console.log('Files:', args.fileDetails.map(f => f.name));
    },
    
    // File loading
    fileLoad: (args) => {
        console.log('Rendering:', args.fileDetails.name);
        console.log('View:', args.module);
        // Can customize rendered element
    },
    
    fileOpen: (args) => {
        console.log('Opening:', args.fileDetails.name);
        if (args.fileDetails.isFile) {
            args.cancel = true;  // Prevent opening
            // Do custom action
        }
    }
});
示例 3:拖放事件
const filemanager = new FileManager({
    // Drag-drop lifecycle
    fileDragStart: (args) => {
        console.log('Drag started:', args.fileDetails.length, 'items');
    },
    
    fileDragging: (args) => {
        console.log('Dragging over:', args.target.id);
    },
    
    fileDragStop: (args) => {
        console.log('About to drop to:', args.target.id);
        // Can cancel with args.cancel = true
    },
    
    fileDropped: (args) => {
        console.log('Dropped successfully');
    }
});
示例 4:UI 交互事件
const filemanager = new FileManager({
    // Toolbar events
    toolbarCreate: (args) => {
        console.log('Toolbar items:', args.items.length);
        // Can modify toolbar items before rendering
    },
    
    toolbarClick: (args) => {
        console.log('Clicked:', args.item.id);
        if (args.item.id === 'CustomButton') {
            args.cancel = true;  // Prevent default
            // Do custom action
        }
    },
    
    // Menu events
    menuOpen: (args) => {
        console.log('Menu opening for:', args.fileDetails.name);
        console.log('Menu items:', args.items.length);
    },
    
    menuClick: (args) => {
        console.log('Menu action:', args.item.id);
        if (args.item.id === 'CustomMenu') {
            // Handle custom menu item
        }
    },
    
    menuClose: (args) => {
        console.log('Menu closed');
    }
});
示例 5:对话框事件
const filemanager = new FileManager({
    // Dialog/popup lifecycle
    beforePopupOpen: (args) => {
        console.log('Dialog opening');
        // Can prevent with args.cancel = true
    },
    
    popupOpen: (args) => {
        console.log('Dialog opened');
    },
    
    beforePopupClose: (args) => {
        console.log('Dialog closing');
    },
    
    popupClose: (args) => {
        console.log('Dialog closed');
    }
});
示例 6:下载、上传和搜索事件
const filemanager = new FileManager({
    ajaxSettings: {
        url: 'https://api.example.com/api/FileManager/FileOperations',
        downloadUrl: 'https://api.example.com/api/FileManager/Download'
    },
    
    // Download events
    beforeDownload: (args) => {
        console.log('Downloading:', args.fileDetails.map(f => f.name));
        if (args.fileDetails.length > 5) {
            alert('Cannot download more than 5 files');
            args.cancel = true;
        }
    },
    
    beforeImageLoad: (args) => {
        console.log('Loading image/thumbnail');
    },
    
    // Upload events
    uploadListCreate: (args) => {
        console.log('Upload item for:', args.fileData.name);
        console.log('Index:', args.index);
    },
    
    // Search events
    search: (args) => {
        console.log('Searching for:', args.searchString);
    }
});
示例 7:完整状态处理
const filemanager = new FileManager({
    ajaxSettings: {
        url: 'https://api.example.com/api/FileManager/FileOperations'
    },
    
    beforeSend: (args) => {
        console.log('Sending request:', args.action);
        // Show loading indicator
        showSpinner();
    },
    
    success: (args) => {
        console.log('✓ Success:', args.action);
        console.log('Result:', args.result);
        hideSpinner();
    },
    
    failure: (args) => {
        console.error('✗ Failure:', args.action);
        console.error('Error:', args.error);
        hideSpinner();
        showErrorMessage(args.error);
    }
});

function showSpinner() { /* Show loading UI */ }
function hideSpinner() { /* Hide loading UI */ }
function showErrorMessage(msg) { console.error(msg); }

UI 模块与注入

不同功能需要向 FileManager 注入特定模块:

可用模块
模块用途导入
Toolbar显示带操作项的工具栏@syncfusion/ej2-filemanager
NavigationPane左侧导航树@syncfusion/ej2-filemanager
DetailsView基于网格的文件列表@syncfusion/ej2-filemanager
模块注入示例
import { FileManager, Toolbar, NavigationPane, DetailsView} from '@syncfusion/ej2-filemanager';

// Inject all modules
FileManager.Inject(Toolbar, NavigationPane, DetailsView);

// Now all features are available
const filemanager = new FileManager({
    view: 'LargeIcons', 
    ajaxSettings: { /* ... */ }
});

常见模式与场景

模式 1:带进度和验证的文件上传
const filemanager = new FileManager({
    ajaxSettings: {
        url: 'https://api.example.com/api/FileManager/FileOperations',
        uploadUrl: 'https://api.example.com/api/FileManager/Upload'
    },
    uploadSettings: {
        maxFileSize: 10485760,      // 10 MB
        minFileSize: 1024,          // 1 KB
        allowedExtensions: ['.pdf', '.doc', '.docx', '.xls', '.xlsx'],
        autoUpload: false           // Manual upload
    },
    uploading: (args) => {
        console.log('Upload progress:');
        args.fileData.forEach(file => {
            console.log(`  ${file.name}: ${file.size} bytes`);
        });
    },
    success: (args) => {
        if (args.action === 'upload') {
            console.log('Upload completed successfully');
        }
    },
    failure: (args) => {
        console.error('Upload failed:', args.error);
    }
});

filemanager.appendTo('#filemanager');
模式 2:带验证的自定义上下文菜单
const filemanager = new FileManager({
    ajaxSettings: {
        url: 'https://api.example.com/api/FileManager/FileOperations'
    },
    contextMenuSettings: {
        file: ['Open', 'Cut', 'Copy', 'Delete', '|', 'Rename', 'Details'],
        folder: ['Open', 'Cut', 'Copy', 'Paste', '|', 'Delete', 'Rename'],
        layout: ['Refresh', 'NewFolder', 'Paste', '|', 'SortBy', 'View']
    },
    menuClick: (args) => {
        if (args.item.text === 'Delete') {
            const confirmed = confirm(`Delete "${args.fileDetails.name}"?`);
            if (!confirmed) {
                args.cancel = true;
            }
        }
    }
});

filemanager.appendTo('#filemanager');
模式 3:使用多选进行批量操作
const filemanager = new FileManager({
    ajaxSettings: {
        url: 'https://api.example.com/api/FileManager/FileOperations'
    },
    allowMultiSelection: true,
    enableRangeSelection: true,
    fileSelect: (args) => {
        const selectedFiles = filemanager.getSelectedFiles();
        console.log(`${selectedFiles.length} files selected`);
        
        // Update bulk action buttons
        updateBulkActionButtons(selectedFiles.length > 0);
    }
});

function bulkDownload() {
    const selected = filemanager.getSelectedFiles();
    if (selected.length > 0) {
        filemanager.downloadFiles();  // Downloads selected files
    }
}

function bulkDelete() {
    const selected = filemanager.getSelectedFiles();
    if (selected.length > 0 && confirm(`Delete ${selected.length} files?`)) {
        filemanager.deleteFiles();  // Deletes selected files
    }
}

filemanager.appendTo('#filemanager');
模式 4:自定义处理拖放
const filemanager = new FileManager({
    ajaxSettings: {
        url: 'https://api.example.com/api/FileManager/FileOperations'
    },
    allowDragAndDrop: true,
    fileDragStart: (args) => {
        console.log('Starting drag operation for:', args.fileDetails.length, 'items');
    },
    fileDragging: (args) => {
        // Check if drop target is valid during dragging
        const isValidTarget = args.target?.classList?.contains('drop-zone');
        if (!isValidTarget) {
            args.element.style.opacity = '0.5';  // Visual feedback
        }
    },
    fileDragStop: (args) => {
        // Perform validation before drop
        console.log('About to drop on:', args.target.id);
    },
    fileDropped: (args) => {
        // Called after successful drop
        const files = args.fileDetails.map(f => f.name);
        console.log('Files dropped successfully:', files);
    }
});

filemanager.appendTo('#filemanager');
模式 5:本地化与 RTL 支持
const filemanager = new FileManager({
    ajaxSettings: {
        url: 'https://api.example.com/api/FileManager/FileOperations'
    },
    locale: 'ar-AE',                    // Arabic (e.g., ar-AE, fr-FR, de-DE)
    enableRtl: true,                    // Right-to-Left rendering
    enablePersistence: true,            // Remember user settings
    cssClass: 'rtl-theme'              // Apply RTL-specific styles
});

// To change language at runtime
function changeLanguage(languageCode) {
    // Destroy current instance
    filemanager.destroy();
    
    // Create new instance with different locale
    const newFileManager = new FileManager({
        locale: languageCode,
        enableRtl: true,
        ajaxSettings: {
            url: 'https://api.example.com/api/FileManager/FileOperations'
        }
    });
    
    newFileManager.appendTo('#filemanager');
}

filemanager.appendTo('#filemanager');
模式 6:访问控制与权限
const filemanager = new FileManager({
    ajaxSettings: {
        url: 'https://api.example.com/api/FileManager/FileOperations',
        beforeSend: (args) => {
            // Add user token for authorization
            args.headers = {
                'Authorization': 'Bearer ' + getUserToken()
            };
        }
    },
    toolbarSettings: {
        items: ['NewFolder', 'Upload', 'Download', 'Delete', 'Refresh']
    },
    menuClick: (args) => {
        // Check permissions before allowing delete
        if (args.item.text === 'Delete' && !userHasPermission('delete')) {
            alert('You do not have permission to delete files');
            args.cancel = true;
        }
    }
});

filemanager.appendTo('#filemanager');
模式 7:全面的文件系统数据结构

包含多种文件类型、嵌套文件夹和可选属性的完整真实示例:

import { FileManager, Toolbar, NavigationPane, DetailsView, LargeIconsView, ContextMenu } from '@syncfusion/ej2-filemanager';

FileManager.Inject(Toolbar, NavigationPane, DetailsView, LargeIconsView, ContextMenu);

// Complete file system data with 19 items showing various scenarios
const fileSystemData = [
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T18:16:38.4384894+05:30"),
        filterPath: "",
        hasChild: true,
        id: '0',
        isFile: false,
        name: "Files",
        parentId: null,
        size: 1779448,
        type: "folder"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\",
        hasChild: false,
        id: '1',
        isFile: false,
        name: "Documents",
        parentId: '0',
        size: 680786,
        type: "folder"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\",
        hasChild: false,
        id: "2",
        isFile: false,
        name: "Downloads",
        parentId: "0",
        size: 6172,
        type: "folder"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\",
        hasChild: false,
        id: "3",
        isFile: false,
        name: "Music",
        parentId: "0",
        size: 20,
        type: "folder"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\",
        hasChild: true,
        id: "4",
        isFile: false,
        name: "Pictures",
        parentId: "0",
        size: 228465,
        type: "folder"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\",
        hasChild: false,
        id: "5",
        isFile: false,
        name: "Videos",
        parentId: "0",
        size: 20,
        type: "folder"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\Documents\\",
        hasChild: false,
        id: "6",
        isFile: true,
        name: "EJ2_File_Manager",
        parentId: "1",
        size: 12403,
        type: "docx"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\Documents\\",
        hasChild: false,
        id: "7",
        isFile: true,
        name: "EJ2_File_Manager",
        parentId: "1",
        size: 90099,
        type: "pdf"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\Documents\\",
        hasChild: false,
        id: "8",
        isFile: true,
        name: "File_Manager_PPT",
        parentId: "1",
        size: 578010,
        type: "pptx"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\Documents\\",
        hasChild: false,
        id: "9",
        isFile: true,
        name: "File_Manager",
        parentId: "1",
        size: 274,
        type: "txt"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\Downloads\\",
        hasChild: false,
        id: "10",
        isFile: true,
        name: "Sample_Work_Sheet",
        parentId: "2",
        size: 6172,
        type: "xlsx"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\Music\\",
        hasChild: false,
        id: "11",
        isFile: true,
        name: "Music",
        parentId: "3",
        size: 10,
        type: "mp3"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\Music\\",
        hasChild: false,
        id: "12",
        isFile: true,
        name: "Sample_Music",
        parentId: "3",
        size: 10,
        type: "mp3"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\Videos\\",
        hasChild: false,
        id: "13",
        isFile: true,
        name: "Demo_Video",
        parentId: "5",
        size: 10,
        type: "mp4"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\Videos\\",
        hasChild: false,
        id: "14",
        isFile: true,
        name: "Sample_Video",
        parentId: "5",
        size: 10,
        type: "mp4"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\Pictures\\",
        hasChild: true,
        id: '15',
        isFile: false,
        name: "Employees",
        parentId: '4',
        size: 237568,
        type: "folder"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\Pictures\\Employees\\",
        hasChild: false,
        id: '16',
        isFile: true,
        name: "Albert",
        parentId: '15',
        size: 53248,
        type: "png",
        imageUrl: "https://ej2.syncfusion.com/demos/src/avatar/images/pic01.png"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\Pictures\\Employees\\",
        hasChild: false,
        id: '17',
        isFile: true,
        name: "Nancy",
        parentId: '15',
        size: 65536,
        type: "png",
        imageUrl: "https://ej2.syncfusion.com/demos/src/avatar/images/pic02.png"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\Pictures\\Employees\\",
        hasChild: false,
        id: '18',
        isFile: true,
        name: "Michael",
        parentId: '15',
        size: 69632,
        type: "png",
        imageUrl: "https://ej2.syncfusion.com/demos/src/avatar/images/pic03.png"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\Pictures\\Employees\\",
        hasChild: false,
        id: '19',
        isFile: true,
        name: "Robert",
        parentId: '15',
        size: 48951,
        type: "png",
        imageUrl: "https://ej2.syncfusion.com/demos/src/avatar/images/pic04.png"
    }
];

const filemanager = new FileManager({
    fileSystemData: fileSystemData,
    height: '100%',
    width: '100%',
    view: 'Details'
});

filemanager.appendTo('#filemanager');

高级集成

自定义文件提供程序集成
class CustomFileProvider {
    async readDirectory(path: string): Promise<any[]> {
        const response = await fetch(`/api/files?path=${path}`);
        return response.json();
    }
    
    async uploadFile(file: File, path: string): Promise<void> {
        const formData = new FormData();
        formData.append('file', file);
        formData.append('path', path);
        await fetch('/api/upload', { method: 'POST', body: formData });
    }
}

const provider = new CustomFileProvider();

const filemanager = new FileManager({
    ajaxSettings: {
        url: '/api/filemanager/operations'
    }
});

filemanager.appendTo('#filemanager');
状态持久化
const filemanager = new FileManager({
    enablePersistence: true,  // Automatically saves:
                              // - Current view (LargeIcons/Details)
                              // - Current path
                              // - Selected items
    
    // Optional: Manual state management
    beforeUnload: () => {
        const state = {
            path: filemanager.path,
            view: filemanager.view,
            selected: filemanager.getSelectedFiles()
        };
        localStorage.setItem('fm-state', JSON.stringify(state));
    }
});

filemanager.appendTo('#filemanager');
大型列表的虚拟滚动
const filemanager = new FileManager({
    ajaxSettings: {
        url: 'https://api.example.com/api/FileManager/FileOperations'
    },
    enableVirtualization: true,         // Enable virtual scrolling
    view: 'Details',                    // Works best with Details view
    height: '500px'                     // Fixed height required
});

filemanager.appendTo('#filemanager');

最佳实践

  1. 始终配置 AJAX 设置

    • 设置正确的服务器端点
    • 包含身份验证令牌
    • 正确处理 CORS
  2. 实现错误处理

    • 使用 failure 事件捕获错误
    • 提供用户友好的错误消息
    • 记录错误以便调试
  3. 优化性能

    • 为大型列表启用虚拟化
    • 对目录使用分页
    • 压缩文件上传内容
  4. 安全注意事项

    • 启用 HTML 清理器
    • 在客户端和服务器端验证文件类型
    • 实现服务器端访问控制
    • 对敏感操作使用 HTTPS
  5. 优化用户体验

    • 设置合理的文件大小限制
    • 清晰展示上传进度
    • 启用拖放以提升便利性
    • 支持键盘快捷键
  6. 本地化支持

    • 设置适当的区域设置
    • 支持从右向左书写语言的 RTL
    • 为自定义项目提供翻译
  7. 测试场景

    • 使用大型文件进行测试
    • 使用各种文件类型进行测试
    • 测试权限场景
    • 在不同浏览器中进行测试

API 兼容性矩阵

功能LargeIconsDetailsToolbarNavigationDownloadUpload
视图切换✓✓✓---
文件选择✓✓✓-✓-
拖放✓✓---✓
上下文菜单✓✓--✓-
排序-✓✓---
搜索✓✓✓---
缩略图✓--✓--
虚拟化-✓-✓--

总结

此全面的 Skill 涵盖:

✅ 100% API 覆盖:记录所有属性、方法和事件
✅ 配置对象:通过示例说明所有设置
✅ 事件处理:提供完整的事件生命周期示例
✅ UI 模块:正确注入和使用模块
✅ 常见模式:真实使用场景
✅ 最佳实践:适用于生产环境的指南
✅ TypeScript 支持:完整的类型安全
✅ 示例:涵盖每项功能的可运行代码

如需了解详细的主题覆盖范围,请参阅上方的导航指南章节。每份参考文档都提供深入说明和更多示例。

评论

支持 Markdown