GrapesJS Asset Manager 完全指南:配置、上传、编程式管理与自定义 UI
2026/9/11 18:52:41 网站建设 项目流程

GrapesJS Asset Manager 完全指南:配置、上传、编程式管理与自定义 UI

【免费下载链接】grapesjsFree and Open source Web Builder Framework. Next generation tool for building templates without coding项目地址: https://gitcode.com/GitHub_Trending/gr/grapesjs

本篇技术指南围绕 GrapesJS 内置的 Asset Manager(资源管理器)模块展开,讲解如何通过assetManager配置初始化资源、配置拖拽上传与后端接口对接、利用全局/可见双集合进行编程式资源管理,以及通过custom配置与asset:custom事件完全替换默认 UI。读完本篇,你将掌握在 GrapesJS 项目中从零配置资源管理器、接入上传服务、自定义选择逻辑与打造独立外部资源管理器的完整实战方案。

模块定位:轻量且可扩展的资源管理核心

GrapesJS 的 Asset Manager 是一个轻量级模块,其核心只内置了image一种资源类型,但设计上极易扩展。在 packages/core/src/asset_manager/model/Assets.ts 中可以确认,image是注册在类型栈中的第一个(也是唯一内置的)类型定义:

Assets.prototype.types = [ { id: 'image', model: AssetImage, view: AssetImageView, isType(value: string) { if (typeof value == 'string') { return { type: 'image', src: value }; } return value; }, }, ];

从源码结构看,资源类型由三部分组成:model(业务逻辑)、view(展示逻辑)与isType(类型识别函数),你可以在此基础上注册自己的videosvg-icon等类型。模块入口位于 packages/core/src/asset_manager/index.ts,其中明确声明storageKey = 'assets',即资源数据会随项目一并持久化存储。

Configuration:初始化配置与运行时读取

要修改默认配置,只需在grapesjs.init时传入assetManager属性:

const editor = grapesjs.init({ // ... assetManager: { assets: [...], // ...其他选项 } });

配置项的大部分可在运行时通过模块的getConfig()读取并更新:

const amConfig = editor.AssetManager.getConfig();

完整的配置类型定义与默认值集中在 packages/core/src/asset_manager/config/config.ts,下表整理了全部可用选项及其源码确认的默认值:

配置项默认值说明
assets[]默认资源列表,支持字符串 URL 或对象
noAssets''无资源可展示时显示的内容
stylePrefix'am-'样式前缀
upload''上传接口地址,为空字符串时不发起 HTTP 上传
uploadName'files'POST 请求中携带文件的字段名
headers{}上传请求的自定义请求头
params{}上传请求的自定义参数(如 CSRF token)
credentials'include'上传请求的 credentials 设置,如'include''omit'
multiUploadtrue是否允许单次请求上传多个文件
multiUploadSuffix'[]'多文件上传时追加到uploadName后的后缀
autoAddtrue上传成功后自动将响应中的资源加入集合
fetchOptionsundefined自定义传给 Fetch API 的选项
customFetchundefined覆盖默认 Fetch 逻辑的自定义请求函数
uploadFileundefined完全接管上传过程的函数
embedAsBase64trueuploadFile/upload时将资源以 Base64 内嵌
handleAddundefined处理内置"添加图片"表单提交的函数
beforeUploadundefined上传前回调,返回false可取消上传
showUrlInputtrue是否显示资源 URL 输入框
customfalse是否使用自定义 UI,可为布尔值或{ open, close }对象
dropzonefalse整编辑器拖拽上传区(已废弃,见下方说明)
openAssetsOnDroptrue拖拽落地后自动打开资源管理器(已废弃)
dropzoneContent''dropzone 内追加的内容(已废弃)

需要注意,配置源码中dropzoneopenAssetsOnDropdropzoneContent三个选项均已标注@deprecated,仅保留兼容,新项目中不应依赖它们。同时,文档中"upload默认false"的说法在现行源码中已演变为默认空字符串'':由 packages/core/src/asset_manager/view/FileUploader.ts 的构造逻辑可见,当upload为空且embedAsBase64true时,上传会被自动降级为"读取为 Base64 数据 URI 加入集合",而非直接禁用。

Initialization:初始化资源集合

Asset Manager 开箱即用,只需在初始化时传入若干 URL 即可看到资源被加载:

const editor = grapesjs.init({ // ... assetManager: { assets: [ 'http://placehold.it/350x250/78c5d6/fff/image1.jpg', // 传对象可携带更多属性 { type: 'image', src: 'http://placehold.it/350x250/459ba8/fff/image2.jpg', height: 350, width: 250, name: 'displayName' }, { // 由于 'image' 是基础类型,省略 type 也会默认为 'image' src: 'http://placehold.it/350x250/79c267/fff/image3.jpg', height: 350, width: 250, name: 'displayName' }, ], } });

资源对象的完整属性可参考 AssetImage Model:

defaults() { return { ...Asset.getDefaults(), type: 'image', unitDim: 'px', height: 0, width: 0, }; }

即除typesrc两个基础字段(定义于 Asset.ts)外,图片类型还支持unitDim(尺寸单位,默认px)、heightwidth,以及可自由扩展的自定义属性。模块在加载阶段会调用this.getAll().reset(this.config.assets)(见 index.ts 的onLoad()),把初始化配置灌入全局集合。另外注意 Asset.ts 底部Asset.prototype.idAttribute = 'src',资源以src作为唯一标识。

内置 Modal 与 open-assets 命令

内置的资源管理器弹窗(Modal)已实现,默认在以下场景自动出现:拖拽图片组件到画布、双击画布中的图片,以及与图片相关的其他操作(如 CSS 样式设置)。其底层由open-assets命令驱动,实现在 packages/core/src/commands/view/OpenAssets.ts。该命令会在run时设置目标、注入select/types行为,并通过editor.Modal.open()(Modal 模块详见 docs/modules/Modal.md)展示渲染结果。因此你也可以手动唤起:

// 该命令默认只展示 `image` 类型的资源 editor.runCommand('open-assets');

若希望选择后能实际修改组件,需要传入目标组件,例如先选中画布中的图片再执行:

// 先确保编辑器全局可用:window.editor = editor; editor.runCommand('open-assets', { target: editor.getSelected() });

命令支持在opts中传入types(展示类型白名单)、accept(上传文件类型过滤)、selecttargetonClickonDblClickonSelectmodalTitle等选项,types会过滤全局集合后渲染,accept会直接设置到上传输入框的accept属性上。

Uploading assets:拖拽上传与后端对接

默认资源管理器自带易用的拖拽上传器,打开资源管理器即可见。你可以点击上传器选择文件,也可以直接把文件从电脑拖入触发上传。要让上传真正工作,需要先准备好接收资源的后端服务,并在配置中指定上传接口:

const editor = grapesjs.init({ // ... assetManager: { // ... // 上传接口地址,设为 false 可禁用上传(现行源码默认为空字符串) upload: 'https://endpoint/upload/assets', // POST 请求中传递文件的字段名,默认 'files' uploadName: 'files', // ... }, // ... });

上传请求的构成

结合 FileUploader.ts 的实现,一次上传请求大致如下:

  • 请求方法为POSTcredentials默认'include'
  • 请求头默认附带X-Requested-With: XMLHttpRequest(可通过headers覆盖或追加);
  • multiUploadtrue,每个文件以${uploadName}${multiUploadSuffix}(即默认files[])为字段名逐个appendFormData;否则只传第一个文件,字段名为uploadName
  • params中的键值对会一并追加进FormData
  • 上传前会执行beforeUpload(files),返回false则取消上传;
  • 默认使用 Fetch API,可通过fetchOptions调整请求选项(如改为method: 'put'),或用customFetch(url, options)完全替换请求逻辑(应返回 Promise);
  • 若提供uploadFile(ev, clb, opts),则整个上传流程由你接管,但需要自行触发所有asset:upload:*事件;
  • 在没有uploadFileupload为空、embedAsBase64true时,文件会被FileReader读取为 Base64 数据 URI 并解析出宽高后加入集合(见embedAsBase64静态方法)。

Listeners:上传生命周期监听

若想在流程前后执行动作(如加载动画)或处理响应,可订阅这些事件:

// 上传开始 editor.on('asset:upload:start', () => { startAnimation(); }); // 上传结束(无论成功与否) editor.on('asset:upload:end', () => { endAnimation(); }); // 错误处理 editor.on('asset:upload:error', (err) => { notifyError(err); }); // 收到响应后处理 editor.on('asset:upload:response', (response) => { // ... });

Response:服务端响应格式

上传完成后,默认(autoAdd: 1)编辑器期望在响应的data键中收到一个 JSON 数组,并自动将其加入全局集合。JSON 形如:

{ data: [ 'https://.../image.png', // ... { src: 'https://.../image2.png', type: 'image', height: 100, width: 200, }, // ... ]; }

源码中onUploadResponse会先触发asset:upload:response事件,随后当config.autoAdd && target成立时执行target.add(json.data, { at: 0 })(插入到集合头部)。target即全局集合,因此只要响应格式正确,上传的资源会立即出现在面板中。

Programmatic usage:编程式管理资源

资源的一切编程式操作都通过模块 API 完成,先获取模块实例:

const am = editor.AssetManager;

Asset Manager 内部维护两个资源集合(见 index.ts 构造函数中的同步逻辑):

  • global:全部可用资源所在集合,通过am.getAll()获取;
  • visible:当前实际渲染在面板中的集合,通过am.getAllVisible()获取。

构造时全局集合上add/remove事件会自动同步到可见集合,这让你可以自由决定"何时展示哪些资源"。假设要做分类切换器,先把所有资源(也可在初始化时通过config.assetManager.assets定义)加入全局集合:

am.add([ { // 可传任意自定义属性 category: 'c1', src: 'http://placehold.it/350x250/78c5d6/fff/image1.jpg', }, { category: 'c1', src: 'http://placehold.it/350x250/459ba8/fff/image2.jpg', }, { category: 'c2', src: 'http://placehold.it/350x250/79c267/fff/image3.jpg', }, // ... ]);

render()无参调用时会渲染全部资源:

// 不带任何参数 am.render(); am.getAll().length; // <- 3 am.getAllVisible().length; // <- 3

接着只展示第一个分类的资源:

const assets = am.getAll(); am.render(assets.filter((asset) => asset.get('category') == 'c1')); am.getAll().length; // 仍是 3 个资源 am.getAllVisible().length; // 但只展示 2 个

也可以混合多个数组渲染:

am.render([...assets1, ...assets2, ...assets3]);

更新或删除资源:

// 通过 src 获取资源 const asset = am.get('http://.../img.jpg'); // 更新资源属性 asset.set({ src: 'http://.../new-img.jpg' }); // 删除资源(传资源对象或 src 均可) am.remove(asset); // 或 am.remove('http://.../new-img.jpg');

更多 API 方法(opencloseisOpengetContaineraddTypegetType等)可查阅 API 参考。从源码可见,add()默认把新资源插入集合头部(opts.at = 0),get(src)通过idAttribute = 'src'按 URL 精确查找,remove则委托给通用删除逻辑。

Custom select logic:自定义选择逻辑

本节内容适用于 GrapesJS v0.17.26 及以上版本。

你可以用自定义选择逻辑打开资源管理器:

am.open({ types: ['image'], // 默认选项 // 不传 select 时,选中资源不会有任何动作 select(asset, complete) { const selected = editor.getSelected(); if (selected && selected.is('image')) { selected.addAttributes({ src: asset.getSrc() }); // 默认 UI 单击时触发 select(asset, false),双击时触发 select(asset, true) complete && am.close(); } }, });

open()内部本质是执行open-assets命令(见 index.ts 的open()),把typesselect合并进命令选项;am.close()am.isOpen()则分别对应命令的 stop 与激活状态判断。

Customization:自定义 UI 与外部资源管理器

默认 UI 适合简单场景,但诸如搜索框、筛选器等复杂功能需要替换默认 UI。做法是开启custom配置并订阅asset:custom事件:

const editor = grapesjs.init({ // ... assetManager: { // ... custom: true, }, }); editor.on('asset:custom', (props) => { // props.open (boolean) - 资源管理器是否处于打开状态 // props.assets (Array<Asset>) - 全部资源数组 // props.types (Array<String>) - 被请求的资源类型,如 ['image'] // props.close (Function) - 关闭资源管理器的回调 // props.remove (Function<Asset>) - 删除资源的回调 // props.select (Function<Asset, boolean>) - 选中资源的回调 // props.container (HTMLElement) - 应挂载你 UI 的容器元素 // 在这里编写渲染/更新 UI 的逻辑 });

自定义 UI 时,把挂载后的元素追加到容器是必须的:props.container.appendChild(this.$el);,因为默认情况下资源管理器位于 Modal 中(asset:custom事件的数据结构定义见 packages/core/src/asset_manager/types.ts 的AssetsCustomData)。

如果资源管理器是完全独立的外部模块(例如应展示在它自己的弹窗中),可通过assetManager.custom.open绑定状态:

const editor = grapesjs.init({ // ... assetManager: { // ... custom: { open(props) { // props 与 `asset:custom` 事件中的一致 // ... // 初始化并打开你的外部资源管理器 // ... // 重要: // 外部库关闭时必须把状态回传给编辑器, // 否则 GrapesJS 会以为资源管理器仍处于打开状态。 // 示例:myAssetManager.on('close', () => props.close()) }, close(props) { // 关闭外部资源管理器 }, }, }, });

必须声明close函数,编辑器才能通过am.close()关闭外部资源管理器。这与 OpenAssets.ts 中的实现一致:当custom.open/custom.close为函数时,命令的open/close会分别委托给它们;否则走默认的 Modal 流程。同时,custom模式下render()会被跳过(见 index.ts 的render()首行判断),渲染职责完全交给自定义 UI。

Events:完整事件一览

资源模块的全部事件定义于 packages/core/src/asset_manager/types.ts 的AssetsEvents枚举,汇总如下:

事件触发时机回调参数
asset:add新资源加入集合asset
asset:remove资源被移除asset
asset:remove:before资源移除前asset
asset:update资源属性更新asset, updatedProps
asset:open资源管理器打开
asset:close资源管理器关闭
asset:upload:start上传开始
asset:upload:end上传结束result
asset:upload:error上传出错error
asset:upload:response收到上传响应res
asset:custom自定义 UI 需要更新时AssetsCustomData
asset上述所有事件的汇总(catch-all)事件数据对象

在 index.ts 的__propEv中可以看到,每个事件都会同时通过em.trigger(ev)广播到编辑器实例,并触发全局集合上同名事件,因此无论从editor.on(...)还是集合层面都能订阅。

延伸阅读

  • 资源模块完整 API:docs/api/assets.md
  • 配置项类型定义:packages/core/src/asset_manager/config/config.ts
  • 模块实现与全局/可见集合同步逻辑:packages/core/src/asset_manager/index.ts
  • 基础资源模型与图片模型:Asset.ts、AssetImage.ts
  • 上传实现(含 Base64 降级逻辑):FileUploader.ts
  • 资源视图基类与图片视图:AssetView.ts、AssetImageView.ts
  • open-assets命令实现:OpenAssets.ts

【免费下载链接】grapesjsFree and Open source Web Builder Framework. Next generation tool for building templates without coding项目地址: https://gitcode.com/GitHub_Trending/gr/grapesjs

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询