news 2026/9/11 3:42:49

GrapesJS Asset Manager 模块 API 详解:从资产集合管理到自定义 UI

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
GrapesJS Asset Manager 模块 API 详解:从资产集合管理到自定义 UI

GrapesJS Asset Manager 模块 API 详解:从资产集合管理到自定义 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(资源管理器)负责统一管理编辑器中的所有媒体资源(图片、SVG、文档等),并为它们提供可视化的选择、上传与展示界面。本文以官方 API 文档为主体,结合仓库源码(asset_manager 模块)深入讲解该模块的配置、事件系统、全部公开方法以及底层实现原理,读完你可以熟练地在自己的 GrapesJS 应用中完成资产初始化、程序化增删改查、接入上传服务乃至用自定义 UI 完全替换默认界面。

模块初始化与配置对象

你可以在编辑器初始化时通过assetManager配置项定制该模块的初始状态,传入一个配置对象:

const editor = grapesjs.init({ assetManager: { // options } });

编辑器实例化之后,即可通过实例获取模块,进而调用其 API:

const assetManager = editor.AssetManager;

核心配置项一览

结合 config.ts 中的AssetManagerConfig接口与其默认值,模块支持以下关键配置:

配置项默认值说明
assets[]默认资产列表,支持字符串 URL 或对象:['https://...image1.png', {type: 'image', src: 'https://...image2.png', someOtherCustomProp: 1}]
noAssets''无资产可展示时显示的内容,例如'No <b>assets</b> here, drag to upload'
stylePrefix'am-'样式前缀
upload''上传接口地址,设为false可禁用上传,例如'https://endpoint/upload/assets'
uploadName'files'POST 上传时携带文件的字段名
headers{}上传请求的自定义请求头
params{}上传请求的自定义参数(如 CSRF token)
credentials'include'上传请求的 credentials 设置,可选'include''omit'
multiUploadtrue是否允许一次请求上传多个文件,关闭后文件名不会附加multiUploadSuffix
multiUploadSuffix'[]'multiUpload开启时追加到uploadName后的后缀
autoAddtrue上传成功后自动将响应中的资产加入集合;要求服务端返回{ data: [...] }格式的 JSON
fetchOptions-定制传给默认 Fetch API 的选项,如(options) => ({ ...options, method: 'put' })
customFetch-用自定义逻辑覆盖 Fetch 上传,需返回 Promise,如(url, options) => axios(url, { data: options.body })
uploadFile-完全接管上传流程的自定义函数,此时需自行触发全部asset:upload:*事件
embedAsBase64true在既无uploadFile也无upload时,将资产以 Base64 形式内嵌
handleAdd-处理内置「添加图片」表单提交,如(textFromInput) => editor.AssetManager.add(textFromInput)
beforeUpload-上传前回调,返回false可取消上传
showUrlInputtrue是否显示资产 URL 输入框
customfalse避免渲染默认资产管理器,可传布尔值或{ open, close }对象
dropzone/openAssetsOnDrop/dropzoneContentfalse/true/''全编辑器拖放上传相关配置(在源码中已标记为@deprecated

从源码可以看出,模块在构造时会先执行defConfig()得到上述默认配置,并将pStylePrefix拼接到stylePrefix前(index.ts)。初始化完成后,onLoad()会用this.config.assets重置全局集合(index.ts),即配置中的assets数组会成为资产的初始来源。

事件系统(Available Events)

Asset Manager 通过editor.on(...)暴露一套完整的事件。事件定义集中在 types.ts 的AssetsEvents枚举中,事件触发时源码会通过__propEv同时通知编辑器与全局集合(index.ts)。全部事件如下:

集合增删改事件

asset:add—— 新资产加入集合,回调参数为该资产对象:

editor.on('asset:add', (asset) => { ... });

asset:remove—— 资产从集合中移除,回调参数为该资产:

editor.on('asset:remove', (asset) => { ... });

(源码还额外定义了asset:remove:before,在移除前触发,见 types.ts)

asset:update—— 资产被更新,回调参数为资产对象和变更内容对象:

editor.on('asset:update', (asset, updatedProps) => { ... });

打开与关闭事件

asset:open—— 资产管理器被打开:

editor.on('asset:open', () => { ... });

asset:close—— 资产管理器被关闭:

editor.on('asset:close', () => { ... });

源码中,这两个事件由open-assets命令的运行/停止回调触发(index.ts),因此asset:open/asset:close实际与命令open-assets的生命周期绑定。

上传事件

asset:upload:start—— 上传开始:

editor.on('asset:upload:start', () => { ... });

asset:upload:end—— 上传结束(无论成功与否):

editor.on('asset:upload:end', (result) => { ... });

asset:upload:error—— 上传出错:

editor.on('asset:upload:error', (error) => { ... });

asset:upload:response—— 收到上传响应:

editor.on('asset:upload:response', (res) => { ... });

自定义 UI 事件

asset:custom—— 供自定义 Asset Manager UI 使用(详见下文「自定义 UI」一节):

editor.on('asset:custom', ({ container, assets, ... }) => { ... });

兜底事件

asset—— 以上所有事件的统称,回调参数为包含本次事件全部可用数据的对象:

editor.on('asset', ({ event, model, ... }) => { ... });

配合 TypeScript 使用时,可参考AssetsEventCallback接口获取每个事件的精确回调签名(types.ts)。

公开方法详解

模块公开了 9 个方法,其实现全部位于 index.ts 中。下面逐个说明。

open —— 打开资产管理器

打开资产管理器,支持传入选项对象:

assetManager.open({ select(asset, complete) { const selected = editor.getSelected(); if (selected && selected.is('image')) { selected.addAttributes({ src: asset.getSrc() }); // 默认 AssetManager UI 会在单击资产时触发 select(asset, false) // 在双击资产时触发 select(asset, true) complete && assetManager.close(); } } }); // 指定自定义类型(前提是已声明了对应类型的资产) assetManager.open({ types: ['doc'], ... });

参数说明:

  • options(Object,可选,默认{}):
    • options.typesArray<String>,默认['image']):要展示的资产类型;
    • options.selectFunction,可选):资产被选中时执行的操作,若不指定则什么都不会发生。

从源码看,open()实际上是运行了内部命令open-assetsconst assetCmd = 'open-assets'),并把types: ['image']与一个空的select作为默认值合入选项后交给cmd.run(index.ts)。这意味着你也可以直接用editor.runCommand('open-assets', {...})达到相同效果。

close —— 关闭资产管理器

assetManager.close();

源码实现为cmd.stop(assetCmd),即停止open-assets命令(index.ts),随后会触发asset:close事件。

isOpen —— 检测是否处于打开状态

assetManager.isOpen(); // true | false

返回Boolean。实现上通过cmd.isActive(assetCmd)判断open-assets命令是否处于激活状态(index.ts)。

add —— 添加新资产

向集合中添加一个或多个资产,URL 假定唯一:

// 以字符串形式 assetManager.add('http://img.jpg'); assetManager.add(['http://img.jpg', './path/to/img.png']); // 使用对象可指定类型及更多元信息 assetManager.add({ // type: 'image', // image 为默认类型 src: 'http://img.jpg', height: 300, width: 200, }); assetManager.add([{ src: 'img2.jpg' }, { src: 'img2.png' }]);

参数说明:

  • assetString | Object | Array<String> | Array<Object>,URL 字符串或表示资源的对象;
  • opts(Object,可选,默认{})。

返回新增的Asset。源码中,若未显式指定opts.at,会默认置为0,即新资产插入到集合头部(index.ts)。传入字符串时,Assets.ts 中注册的image类型isType函数会把字符串统一转换为{ type: 'image', src: value }对象。

get —— 按 URL 查询资产

const asset = assetManager.get('http://img.jpg');

参数:src(String)—— 资产的 URL。

返回Asset | null。实现为this.all.where({ src })[0] || null(index.ts)。之所以能按src精确匹配,是因为 Asset 模型的idAttribute被设置为'src'(见 Asset.ts),这正是文档强调「URLs are supposed to be unique」的根本原因。

getAll —— 获取全局集合

返回包含全部资产的全局集合:

assetManager.getAll(); // Collection<Asset>

返回Collection<Asset>

getAllVisible —— 获取可见集合

返回可见集合,即当前实际被渲染出来的资产:

assetManager.getAllVisible(); // Collection<Asset>

返回Collection<Asset>「全局集合」与「可见集合」是理解该模块的关键:模块构造时创建了独立的assetsVis集合,并建立同步关系——全局集合新增资产时同步加入可见集合,移除时同步移出(index.ts)。render()方法会执行this.assetsVis.reset(toRender)来重置可见集合(index.ts),从而决定渲染哪些资产。

remove —— 移除资产

const removed = assetManager.remove('http://img.jpg'); // 或传入 Asset 对象 const asset = assetManager.get('http://img.jpg'); assetManager.remove(asset);

参数:assetString | Asset)—— 资产或其 URL;optsRemoveOptions,可选)。

返回被移除的Asset。方法内部委托给基类Module__remove完成(index.ts)。

getContainer —— 获取容器元素

返回 Asset Manager 的容器:

assetManager.getContainer(); // HTMLElement

返回HTMLElement。实现优先返回行为配置中的container,否则返回默认视图的根元素this.am?.el(index.ts)。你可以在拿到容器后直接向其中插入自定义 DOM。

Asset 模型 API

文档中出现的[Asset]即资产模型实例,其定义与全部方法见 Asset.ts(对应 API 文档 asset.md)。

核心属性

  • type(String)—— 资产类型,如'image'
  • src(String)—— 资产 URL,如'https://.../image.png'

默认的image类型在此基础上扩展了unitDim'px')、heightwidth属性(见 AssetImage.ts)。

实例方法

getType()—— 获取资产类型:

// Asset: { src: 'https://.../image.png', type: 'image' } asset.getType(); // -> 'image'

返回String,实现为this.get('type')

getSrc()—— 获取资产 URL:

// Asset: { src: 'https://.../image.png' } asset.getSrc(); // -> 'https://.../image.png'

返回String,实现为this.get('src') || ''

getFilename()—— 基于src获取文件名:

// Asset: { src: 'https://.../image.png' } asset.getFilename(); // -> 'image.png' // Asset: { src: 'https://.../image' } asset.getFilename(); // -> 'image'

返回String。源码实现为this.getSrc().split('/').pop().split('?').shift(),即截取最后一个/之后、去掉查询字符串的部分(Asset.ts)。

getExtension()—— 基于src获取扩展名:

// Asset: { src: 'https://.../image.png' } asset.getExtension(); // -> 'png' // Asset: { src: 'https://.../image' } asset.getExtension(); // -> ''

返回String,实现为this.getFilename().split('.').pop()(Asset.ts)。注意无扩展名时返回空字符串而非undefined

上传流程的源码级拆解

模块的默认 UI 内置了拖放上传器(FileUploader.ts)。完整上传链路如下:

  1. 选择文件:点击上传区选择文件或直接拖拽,change [data-input]事件触发uploadFile
  2. 文件过滤:根据accept属性校验文件类型(源码注释 #6032 说明浏览器在拖拽场景不会强制校验accept,因此实现了isFileAccepted辅助函数进行过滤,被全部拒绝时不执行任何操作);
  3. 前置钩子:调用beforeUpload(files),返回false则取消上传;
  4. 构造请求体:将params中的自定义参数追加到FormData;若multiUploadtrue,每个文件以uploadName + multiUploadSuffix(默认files[])为字段名追加,否则只追加第一个文件;
  5. 发起请求:自动补充X-Requested-With: XMLHttpRequest请求头(若未自定义),使用fetchmethod: 'post'credentials按配置)或customFetch;若配置了fetchOptions则先对其结果做转换;
  6. 响应处理onUploadResponse解析 JSON,触发asset:upload:response,若autoAddtrue则把json.data中的资产以{ at: 0 }插入全局集合,最后触发asset:upload:end
  7. 错误处理:请求失败时onUploadError打印错误、触发asset:upload:error,并同样以onUploadEnd收尾。

Base64 内嵌模式:当既未配置upload也未配置uploadFileembedAsBase64true时,模块使用FileReader将文件读取为 Data URL(embedAsBase64静态方法);对图片类型还会额外加载Image对象以探测宽高,一并写入资产数据(FileUploader.ts)。这种模式下asset:upload:start不会触发(因为根本没有网络请求)。

服务端响应须符合如下 JSON 结构(autoAdd: true时才会被自动入库):

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

实战组合:打开管理器并应用到选中组件

opengetSrcclose组合起来,即可实现「打开资产管理器 → 选择图片 → 应用到画布中选中的图片组件」的完整闭环:

const assetManager = editor.AssetManager; assetManager.open({ types: ['image'], // 默认值 select(asset, complete) { const selected = editor.getSelected(); if (selected && selected.is('image')) { selected.addAttributes({ src: asset.getSrc() }); // 单击触发 select(asset, false),双击触发 select(asset, true) complete && assetManager.close(); } }, });

若不加select回调,资产选择时不会有任何动作(对应源码open()中默认的select: () => {})。此外,使用全局/可见双集合机制还可以实现「分类筛选」这类高级交互:先向全局集合addcategory属性的资产,再用render()传入过滤后的资产数组控制可见集合(完整示例见 Assets 模块指南)。

自定义 UI 与类型扩展

使用asset:custom替换默认界面

默认 UI 仅适合简单场景;若要加入搜索框、过滤器等复杂功能,可设置custom: true并订阅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 的逻辑 });

从源码看,asset:custom__trgCustom触发,其数据由__customData()组装,除上述字段外还包含am(模块实例)与options(本次打开时的选项);并且仅在存在container或配置了custom.open时才会触发(index.ts)。

若你的 UI 是完全独立的外部模块(例如自己的弹窗),可改用对象形式的配置,并务必实现close,否则编辑器无法通过am.close()关闭:

const editor = grapesjs.init({ // ... assetManager: { // ... custom: { open(props) { // props 与 asset:custom 事件中的一致 // 初始化并打开外部资产管理器 // 外部库关闭时须调用 props.close() 同步状态 // 例如:myAssetManager.on('close', () => props.close()) }, close(props) { // 关闭外部资产管理器 }, }, }, });

注册自定义资产类型

模块核心只实现了image一种类型(见 Assets.ts 的types注册表),但通过addType(id, definition)可以轻松扩展。定义由model(业务逻辑)、view(展示逻辑)与isType(类型识别函数)三部分组成:

assetManager.addType('my-type', { model: {}, view: {}, isType: (value) => {}, });

视图层基于 AssetView.ts 的template()/getPreview()/getInfo()/updateTarget()钩子实现,AssetImageView.ts 即是最好的参考实现。更完整的自定义类型开发流程(含 SVG 资产案例与类型继承)请参阅 Assets 模块指南。

小结

Asset Manager 是一个「轻核心、可扩展」的模块:核心仅内置image类型,但通过add/get/getAll/getAllVisible/remove等 API 支撑起全局集合与可见集合的双层管理,通过open/close/isOpenopen-assets命令联动控制界面显隐,通过asset:*事件族覆盖增删改、开关与上传全链路,最后以asset:custom+custom配置为完全自定义 UI 留下入口。理解了集合、命令与事件这三条主线,你就能在项目中灵活驾驭它。

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

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 3:41:12

PCSX2 PS2 模拟器避坑指南:跑起游戏、拉帧数,一次搞定

PCSX2 PS2 模拟器避坑指南&#xff1a;跑起游戏、拉帧数&#xff0c;一次搞定 【免费下载链接】pcsx2 PCSX2 - The Playstation 2 Emulator 项目地址: https://gitcode.com/GitHub_Trending/pc/pcsx2 摊开一张老 PS2 光盘镜像&#xff0c;PCSX2 这款 PS2 模拟器能让主机…

作者头像 李华
网站建设 2026/9/11 3:37:16

SpringBoot校园电动车租赁系统设计与实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 3:23:32

GitHub热榜项目实战:从AI应用到效率工具的上手指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 3:23:15

MuJoCo 物体总滑动?用摩擦参数速查表快速定位原因

MuJoCo 物体总滑动&#xff1f;用摩擦参数速查表快速定位原因 【免费下载链接】mujoco Multi-Joint dynamics with Contact. A general purpose physics simulator. 项目地址: https://gitcode.com/GitHub_Trending/mu/mujoco MuJoCo 是一款通用物理仿真器&#xff0c;接…

作者头像 李华
网站建设 2026/9/11 3:21:56

功耗优化工程师如何转向Linux内核驱动开发

1. 这不是转行&#xff0c;是功耗优化工程师的自然演进路径干了两年功耗优化&#xff0c;现在该不该转Linux驱动&#xff1f;——这个问题我听到过不下二十次&#xff0c;每次都是在茶水间、技术分享会后&#xff0c;或者深夜改完最后一版PMIC寄存器配置时&#xff0c;同事靠过…

作者头像 李华