报告设计器
在渲染时,为后端填充数据,构建可视化报告和文档布局。
26k+
GitHub 星
1.4M+
npm 下载量/月
100+
GJS.Market 上的插件
$0
许可证费,永远
三个真正的 GrapesJS 编辑器,只有在你要求时才加载。这些演示都不是 Angular 应用——这正是它的意义所在。GrapesJS 渲染成它拥有的容器元素,所以编辑表面看起来和行为都和托管页面的框架一样。
库存编辑器:画布、块、图层树、样式管理器和设备切换器。这是你在添加自己块之前的基础。
加载来自grapesjs.com的第三方实时编辑器。
构建页面构建器远不止几个Angular组件。一个生产准备的可视化编辑器需要这些元素,才能发布带有它的页面:
GrapesJS 为大部分列表中的可视化编辑提供了基础,因此你的 Angular 应用可以将预算花在产品和业务逻辑上。后两者——项目存储地点和页面如何上线——仍留给你,因为它们必须与基础设施匹配。
GrapesJS 核心在 BSD-3-Clause 许可证(版本 0.23.6)下开源,且在任何规模下均无许可费。
探索GrapesJS同一个引擎,指向六个不同的产品。区别在于你的内容模型、区块和发布目标——而不是编辑。
编辑器是你应用内的一个路径,不是它的替代品。编辑层以上的所有内容都保持Angular团队原本放置的位置。
让你的产品拥有的所有元素,保持不变。
一个懒惰加载的路由,一个拥有容器的组件,以及一个拥有编辑器实例的服务。
可视化编辑引擎,运行在组件提供的容器内。
项目数据、上传和发布成果真正存在的地方。
Angular 拥有你的应用程序。GrapesJS 驱动视觉编辑层。
编辑器没有提供任何顶层或底层的内容。正是这个界限让集成变得足够浅,之后可以移除——编辑器永远不会成为你产品的核心。
阅读Angular集成指南发动机自带的八个子系统。每个都是你自己配置的API,而不是一个你直接接受的黑盒子。
用户通过将组件拖到画布上,重新排序并在允许的位置嵌套来构建页面。
定义可重复使用的组件类型,它们各自有traits、可丢弃的规则以及你自己的行为。
在调色板中为用户提供预定义的剖面和布局,而不是一堆原始的HTML元素。
让用户通过选择和限制的属性面板自定义排版、间距、颜色和布局。
每个断点预览和重新样式页面,使用你定义的设备宽度,而不是固定的设备。
通过资产管理器管理图片和其他项目资产,你可以指向自己的存储。
将已完成的页面保存为可重复使用的起始点,这样下一页就不会是空白。
从编辑器里导出干净的HTML和CSS,或者读取JSON项目,按照你的应用偏好渲染。
本列表中故意没有的:托管、CMS、权限模型和发布基础设施。这些都属于你的应用程序,下面的章节说明它们是如何连接的。
通用的网站建设工具很少是大家想要的产品。编辑器的每一层都可以替换成符合你应用的版本。
每一层都会将编辑器缩小到你的内容模型范围。到了最后一层,用户是在创作你的产品——而不是网站。
注册镜像你自己域对象的组件类型,只暴露后端可操作的 traits,并将其放在块面板的分类下。用户随后使用你的 API 已经理解的定价表或产品网格,而不是用你之后需要解析的任意标记。
// Your content model, not a generic website element.
editor.Components.addType('pricing-table', {
isComponent: (el) => el.dataset?.gjsType === 'pricing-table',
model: {
defaults: {
tagName: 'section',
droppable: false,
traits: ['plan', 'currency', 'billingPeriod'],
},
},
});
editor.Blocks.add('pricing-table', {
label: 'Pricing',
category: 'Your design system',
content: { type: 'pricing-table' },
});一个组件类型和插入它的块。特性名变成了后端读取的字段。
人们用的编辑和放弃的编辑之间的区别,通常取决于第一天调色板里的内容。
你的区块
不要让用户从零开始。
创建可重复使用的模块和模板,与你的应用设计系统相匹配,这样用户构建的每一页都已经符合品牌风格且响应式一致。GJS.Market 附带了可以安装的块集和模板管理器,无需从头创作前五十个。
浏览块与模板GrapesJS 将项目序列化到 JSON,然后交给存储适配器。适配器的功能完全由你决定。
编辑器从不和你的数据库通信。它调用你注册的适配器,适配器调用你已有的API。
editor.Storage.add('angular-backend', {
async load() {
return firstValueFrom(this.http.get(`/api/pages/${this.pageId}`));
},
async store(data) {
return firstValueFrom(this.http.put(`/api/pages/${this.pageId}`, data));
},
});
grapesjs.init({
container,
storageManager: { type: 'angular-backend', autosave: true, stepsBeforeSave: 5 },
});一个定制的存储适配器,连接到你的API。这里没有任何内容是针对GJS.Market的——这是编辑者有文档的存储合同。
组件、样式、页面和资源序列化为JSON文档,你可以存储在任何列或集合中。
存储管理器可以在可配置的更改次数后保存,而不仅仅是在显式操作时保存。
注册一个自定义适配器,并通过Angular的HttpClient路由加载和存储,使用你自己的拦截器和认证头部。
因为每个存档都是文档,保存历史是后台的决定——编辑不需要知道这件事发生过。
当交付路径需要静态输出而非重新渲染时,将渲染标记与项目JSON一起导出。
已发布页面是一个独立的记录,拥有自己的生命周期。将其与编辑写作的草稿分开。
你可以控制项目数据的存储位置。
创作和发布是不同的问题,有不同的失败模式。编辑器解决了第一个问题;第二个问题则留在你的基础设施中,缓存、权限和回滚都已经存在。
已发表成果可以去的地方
把输出写回你组织已经运行的内容系统。
把项目或渲染的标记发布到拥有验证和权限的端点。
在发布时将页面渲染成文件,这样活页就不会承载编辑器的运行时间。
通过应用程序已经用来提供页面的路径存储、转换和提供输出。
把已发布的资产和标记推到边缘,缓存失效由你控制。
从发布操作触发你现有的构建或部署流水线。
GrapesJS 负责创作。你的基础设施可以处理发布。
只需部署一个Angular应用,一个编辑器,以及为每个客户单独的页面世界。
Angular SaaS
Org A
Org B
Org C
这些都不是GrapesJS的功能。编辑器没有租户的概念:它加载分配给它的项目并存储被交还的项目。租户是你的Angular应用和后端实现的——这也是它能匹配你已有的隔离模型的原因。
探索SaaS页面构建器编辑器没有任何东西必须看起来像编辑器。用户触摸的每个表面都可以配置、替换或移除。
把可视化编辑器变成你Angular产品的原生部分。
探索白标页面构建器简短版,分为四个步骤。完整指南——生命周期细节、封装器、无区域变更检测、生产问题——独立于一页,且内容远不止于此。
把编辑器添加到你的应用里。它是一个普通的npm包,没有Angular特定的构建步骤。
将编辑器实例放在可注入服务中,这样组件保持精简,且实例便于共享、模拟和拆解。
容器元素必须在编辑器创建前就已在 DOM 中,因为 GrapesJS 会立即测量它。
当路由离开时调用 destroy。没有它,编辑器会保留其 DOM 监听器,下一次导航时会泄漏实例。
npm install grapesjs一个依赖。不需要针对Angular的专用包装。
import { Injectable, NgZone, inject } from '@angular/core';
import grapesjs, { type Editor } from 'grapesjs';
@Injectable({ providedIn: 'root' })
export class PageBuilderService {
private readonly zone = inject(NgZone);
private editor?: Editor;
create(container: HTMLElement): Editor {
// GrapesJS binds its own DOM listeners to the canvas. Creating it outside
// Angular keeps every drag frame from scheduling change detection.
this.editor = this.zone.runOutsideAngular(() =>
grapesjs.init({
container,
height: '100%',
fromElement: false,
storageManager: false,
})
);
return this.editor;
}
destroy(): void {
this.editor?.destroy();
this.editor = undefined;
}
}服务拥有实例及其生命周期;组件只拥有容器。
import {
AfterViewInit,
Component,
ElementRef,
OnDestroy,
inject,
viewChild,
} from '@angular/core';
import { PageBuilderService } from './page-builder.service';
@Component({
selector: 'app-page-builder',
standalone: true,
template: '<div #canvas class="builder"></div>',
styles: '.builder { height: 100vh; }',
})
export class PageBuilderComponent implements AfterViewInit, OnDestroy {
private readonly builder = inject(PageBuilderService);
private readonly canvas = viewChild.required<ElementRef<HTMLElement>>('canvas');
ngAfterViewInit(): void {
// The container has to be in the DOM first: GrapesJS measures it on init.
this.builder.create(this.canvas().nativeElement);
}
ngOnDestroy(): void {
// Without this the editor keeps its listeners after the route changes.
this.builder.destroy();
}
}视图存在后再创建,视图消失后销毁。这对组合是大部分整合。
GrapesJS 会发出自己的事件,而这些事件并非来自 Angular。协调两者只需几行,但跳过它就会产生每个集成最先出现的两个 bug。
editor.on('storage:end:store', () => {
// Editor events fire outside Angular because the editor was created there.
// Re-enter the zone before touching state the template renders.
this.zone.run(() => this.lastSavedAt.set(new Date()));
});在更新渲染状态的处理程序中重新进入该区域。
在runOutsideAngular内创建编辑器,这样画布交互不会在每一帧都调度变更检测,然后在少数几个实际更新模板渲染状态的事件处理程序中重新进入区域。在无区域应用中,同一批处理程序会更新信号,外部封装器就不再需要了。
更多关于Angular生命周期和区域的信息GrapesJS 需要一个浏览器 DOM。在 Angular SSR 或 Angular 通用中,编辑器只在浏览器中创建——绕过它的路由仍会正常在服务器上渲染。
用isPlatformBrowser守护初始化,并在服务器早期返回。其余路由保持不变:守卫、解析器和周围标记保持服务器渲染的行为,只有编辑器容器是空的。
import { PLATFORM_ID, inject } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
export class PageBuilderComponent implements AfterViewInit {
private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
ngAfterViewInit(): void {
// There is no DOM on the server and GrapesJS needs one, so the editor is
// created in the browser only. The rest of the route still renders on the
// server as usual.
if (!this.isBrowser) return;
this.builder.create(this.canvas().nativeElement);
}
}整个SSR调整:在编辑器创建前先做一次平台检查。
集成是普通的Angular代码,这是值得一提的重点。
编辑器自带类型定义,因此实例、配置和事件在调用站点被类型化。
创建和拆解依赖于 ngAfterViewInit 和 ngOnDestroy——无需在组件树外手动启动。
集成中没有任何内容依赖于运行时模板编译,因此编辑器路由的构建方式就像其他懒散加载的路径一样。
在使用 SSR 时,只有编辑器创建部分被浏览器保护;其余组件正常编译和渲染。
以下所有功能都必须具备,视觉编辑器才可用。唯一的问题是你自己写的是哪一项。
| 能力 | 从零开始 | GrapesJS |
|---|---|---|
| 视觉画布 | 需自行构建 | 已内置 |
| 拖拽 | 需自行构建 | 已内置 |
| 组成部分 | 需自行构建 | 已内置 |
| 区块 | 需自行构建 | 可扩展 |
| 造型 | 需自行构建 | 已内置 |
| 响应式剪辑 | 需自行构建 | 已内置 |
| 资产 | 需自行构建 | 可扩展 |
| 模板 | 需自行构建 | 可扩展 |
| 存储 | 需自行构建 | 可扩展 |
| 出口 | 需自行构建 | 可扩展 |
| Angular 积分 | 需自行构建 | 需集成 |
“可扩展”意味着子系统存在,并且有文档化的API指向你自己的实现——而不是它预先接线到你的后端。已在2026-09-03上与GrapesJS 0.23.6进行验证。
打造你的Angular产品。不要重建视觉编辑引擎。
一个实际工作的构建器最终得到的堆栈。GrapesJS覆盖了第一层;剩下的由你自行组装、安装或购买。
引擎为你提供了编辑界面。在特定产品之上——块色板、模板系统、富文本、持久化、生产退出路径——这些都是 GJS.Market 插件发挥作用的地方。下面的每个列表都是真实产品,价格如图所示。
两列的结尾都是能用的建筑。它们在你两年后还要维护多少不同。
GrapesJS 提供可视化编辑的基础。GJS.Market 插件允许你扩展构建器,增加更多功能,而无需内部构建所有功能。
五种反复出现的形状,以及它们用视觉编辑器真正带来的效果。
为客户目前请求客服更改页面的产品添加可视化编辑。
为每个客户构建定制的编辑环境,而不是把没人想要的CMS交给别人。
无需花一年时间从零开始编写编辑器引擎,就能添加视觉编辑。
让营销人员创建和更改页面,无需开发人员参与每个标题的循环。
创建受控的内部编辑工作流程,在那里可以编辑的内容和可以构建的内容同等重要。
发布视觉编辑器的四种方式。它们有重叠,但起点不同——选错限制会显得晚。
在你自己的Angular应用里构建一个可视化编辑器,由你的团队拥有,并由你的内容模型塑造。这就是这个页面。
把编辑器嵌入到已经存在的应用中,两者间的表面积极小。
可嵌入页面构建器打造面向客户的视觉编辑产品,包含租赁、计划和按客户发布。
SaaS 页面构建器让编辑器看起来和行为都像你自己的产品,甚至连面板中的词汇都一样。
白标页面构建器在另一个框架上构建同样的东西?React、Next.js和Vue的论点是一样的——只是生命周期代码有所变化。 React 页面构建器, Next.js 页面构建器, Vue 页面构建器.
编辑器是一个繁重的应用程序,而已发布的页面则不是。把它们当作一个捆绑包来处理是值得尽早避免的错误。
从不打开构建器的用户绝不应该下载它。懒惰的做法会让编辑器无法进入你的主捆绑包。
在 Angular 区域外创建编辑器,并只在更新渲染状态的处理程序中重新进入。
把资产管理工具分页对照你的API,而不是一次给它几千张图片。
创建编辑器实际显示时的实例,而不是当周围组件挂载时。
发布的输出是HTML和CSS。编辑器本身不需要附带。
编辑器运行时和发布页面不需要有相同的性能要求。
可视化编辑器接受用户创作的内容并将其写回你的系统。这些内容都应存储在该交换的服务器端。
每次加载、存储和发布调用时,检查该用户是否会对该项目采取行动。
从会话中解析租户,绝不要从客户端可以更改的参数中解析。
验证服务器端的类型和大小,并从无法执行上传的源头提供上传。
存储适配器运行在浏览器中。它的端点需要和你 API 其他部分相同的认证。
编辑者可能会嵌入自定义代码,在该标记发送给其他人之前,先在服务器上进行净化处理。
发布改变了公众看到的内容。限制速率,记录数据,并在自身许可下进行门禁。
隐藏按钮会改变UI,而不是API。UI所暗示的每一条规则都必须存在于它背后。
切勿只依赖客户端权限。
需要帮助在Angular应用中集成、扩展或定制GrapesJS吗?我们的团队可以协助集成、定制插件、UI定制和生产实现。
Angular 应用中的可视化编辑器,允许用户通过将组件拖到画布上来组装页面,而无需写标记。Angular 应用拥有路由、认证和数据;编辑器拥有编辑表面。
是的。GrapesJS 是框架无关的:它渲染成你给出的容器元素,所以它在 Angular 组件内工作,就像其他基于 DOM 的库一样。
不——它是Angular页面构建器所基于的视觉编辑引擎。没有官方的Angular封装器;你直接集成核心库,它既是一个组件,也是一个服务。
安装包,将实例保留在可注入服务中,容器进入DOM后在ngAfterViewInit中创建,并在ngOnDestroy中销毁。完整指南涵盖了包装器、区域和生产相关问题。
是的。区块通过区块管理器注册,带有你自己的标签、类别和内容,所以调色板只能包含你产品支持的部分。
是的。组件类型会注册各自的traits、丢弃规则和行为,这就是编辑器从通用HTML缩减到内容模型的方式。
是的。保存的项目可以重新加载作为新页面的起点。如果你不想构建UI,也可以作为插件使用模板库和管理器。
是的。注册一个自定义存储适配器,其加载和存储方法调用你的API到HttpClient,这样拦截器、认证头部和错误处理都能正常应用。
是的。编辑器生成的是JSON文档,从不直接与数据库通信,所以文档存储在哪里完全是后台决定。
是的,而且它是最常见的用途之一:有限的块式调色板、贴合品牌的模板,以及一个发布动作,可以写入你的营销页面所接收到的任何地方。
是的。编辑器取代了基于表单的编辑界面;你的CMS保留内容类型、工作流程和权限的所有权。
是的。用traits注册你自己的现场组件作为组件类型进行验证和命名,这样用户组装的组件映射到后端能理解的模式上。
是的,但租户是你应用的工作。编辑器没有租户的概念——你的后台负责解析当前用户可能看到的项目、资产和模板。
是的。面板、图标、颜色、块类和术语都可以配置,你可以通过自己的 Angular UI 命令 API 驱动编辑器。
周围路由在服务器上正常渲染;编辑器本身仅在浏览器中创建。守卫初始化时使用isPlatformBrowser,并在服务器早期返回。
在runOutsideAngular里创建编辑器,这样画布交互不会持续触发变更检测,然后在少数更新模板渲染状态的事件处理程序中使用NgZone.run。
是的。GrapesJS 发布了自己的类型定义,因此编辑器实例、配置对象和事件都用普通的 Angular TypeScript 代码库类型化。
是的。插件是接收编辑器并注册组件、块、命令或面板的功能。GJS.Market 列出了免费和商业插件,用于块、富文本、存储、资源和导出。
应用用Angular,视觉编辑用GrapesJS。添加你自己的组件、模块、模板、存储和发布流程——需要时再用GJS.Market插件扩展构建器。
安装编辑器,挂载到Angular组件内的容器上,下午屏幕上就有东西。
开始模块、模板、富文本、存储和导出——安装产品所需的功能,而不是自己写。
浏览插件生命周期、区域、SSR、封装器和生产检查表,在集成页面端到端都有覆盖。
查看Angular指南你的Angular应用。你的编辑器。你的产品。