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'等 |
multiUpload | true | 是否允许一次请求上传多个文件,关闭后文件名不会附加multiUploadSuffix |
multiUploadSuffix | '[]' | multiUpload开启时追加到uploadName后的后缀 |
autoAdd | true | 上传成功后自动将响应中的资产加入集合;要求服务端返回{ data: [...] }格式的 JSON |
fetchOptions | - | 定制传给默认 Fetch API 的选项,如(options) => ({ ...options, method: 'put' }) |
customFetch | - | 用自定义逻辑覆盖 Fetch 上传,需返回 Promise,如(url, options) => axios(url, { data: options.body }) |
uploadFile | - | 完全接管上传流程的自定义函数,此时需自行触发全部asset:upload:*事件 |
embedAsBase64 | true | 在既无uploadFile也无upload时,将资产以 Base64 形式内嵌 |
handleAdd | - | 处理内置「添加图片」表单提交,如(textFromInput) => editor.AssetManager.add(textFromInput) |
beforeUpload | - | 上传前回调,返回false可取消上传 |
showUrlInput | true | 是否显示资产 URL 输入框 |
custom | false | 避免渲染默认资产管理器,可传布尔值或{ open, close }对象 |
dropzone/openAssetsOnDrop/dropzoneContent | false/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.types(Array<String>,默认['image']):要展示的资产类型;options.select(Function,可选):资产被选中时执行的操作,若不指定则什么都不会发生。
从源码看,open()实际上是运行了内部命令open-assets(const 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' }]);参数说明:
asset:String | 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);参数:asset(String | Asset)—— 资产或其 URL;opts(RemoveOptions,可选)。
返回被移除的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')、height、width属性(见 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)。完整上传链路如下:
- 选择文件:点击上传区选择文件或直接拖拽,
change [data-input]事件触发uploadFile; - 文件过滤:根据
accept属性校验文件类型(源码注释 #6032 说明浏览器在拖拽场景不会强制校验accept,因此实现了isFileAccepted辅助函数进行过滤,被全部拒绝时不执行任何操作); - 前置钩子:调用
beforeUpload(files),返回false则取消上传; - 构造请求体:将
params中的自定义参数追加到FormData;若multiUpload为true,每个文件以uploadName + multiUploadSuffix(默认files[])为字段名追加,否则只追加第一个文件; - 发起请求:自动补充
X-Requested-With: XMLHttpRequest请求头(若未自定义),使用fetch(method: 'post'、credentials按配置)或customFetch;若配置了fetchOptions则先对其结果做转换; - 响应处理:
onUploadResponse解析 JSON,触发asset:upload:response,若autoAdd为true则把json.data中的资产以{ at: 0 }插入全局集合,最后触发asset:upload:end; - 错误处理:请求失败时
onUploadError打印错误、触发asset:upload:error,并同样以onUploadEnd收尾。
Base64 内嵌模式:当既未配置upload也未配置uploadFile且embedAsBase64为true时,模块使用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, }, // ... ]; }实战组合:打开管理器并应用到选中组件
将open、getSrc、close组合起来,即可实现「打开资产管理器 → 选择图片 → 应用到画布中选中的图片组件」的完整闭环:
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: () => {})。此外,使用全局/可见双集合机制还可以实现「分类筛选」这类高级交互:先向全局集合add带category属性的资产,再用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/isOpen与open-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),仅供参考