GrapesJS + Vue 3

GrapesJS Vue:用 Vue 3 构建一个可视化编辑器

将开源的 GrapesJS 可视化编辑器集成到 Vue 3 和 Nuxt 应用程序中,构建可视化页面构建器、CMS 编辑器、着陆页构建器、电子邮件编辑器以及白标编辑体验。

Vue 3Composition APITypeScript开源HTML 与 CSS可扩展性
编辑的位置

Vue驱动你的应用程序。GrapesJS驱动编辑。

这个分割值得在任何代码之前先说明。你的 Vue 应用拥有路由、用户、权限和数据。GrapesJS 拥有画布以及用户在其中操作的所有东西。两者在一个 DOM 节点和一个存档调用处相连。

  1. Vue 3 application
  2. GrapesJS editor
  3. HTML + CSS + project data
  4. Your API / CMS / SaaS

这条链中没有任何东西需要 Vue 来知道编辑器的工作原理,也不需要 GrapesJS 才能知道它在 Vue 应用里。这就是为什么集成时间很短。

简短回答

你能用GrapesJS和Vue一起使用吗?

是的。GrapesJS 与框架无关,可以直接集成到 Vue 3 应用中。你可以用 Vue 生命周期钩子初始化编辑器,将编辑器实例保留在可组合或组件中,将 GrapesJS 事件连接到你的 Vue 应用,并通过自己的后端持久化项目数据。

有两种做法

直接积分

导入葡萄,调用grapesjs.init()在onMounted(),调用editor.destroy()在onUnmounted()。没有额外的依赖,你和编辑器API之间没有任何关联。

一个面向Vue的层

将生命周期包裹在你自己的组合软件或社区包中,使组件获得类似Vue的API而非命令式API。当多个屏幕挂载一个编辑器时,这非常有用。

GrapesJS 发布了一个官方框架包装器 @grapesjs/react,用于 React。GrapesJS 项目没有对应的 Vue 包,因此你在 npm 上找到的任何 Vue 包装器都是社区项目。在采用之前,请查看其 Vue 和 GrapesJS 的对等范围。

劳动分工

Vue的GrapesJS是什么?

Vue 3 是一个应用框架。GrapesJS 是一个可视化编辑引擎。它们解决不同的问题,集成之所以干净,正是因为它们没有重叠。

你的Vue代码
  • 布线
  • 认证
  • 权限
  • 应用界面
  • API和数据层
在GrapesJS中
  • Canvas
  • Drag & drop
  • Component tree
  • Block Manager
  • Style Manager
  • Device Manager
  • UndoManager
  • Commands
  • Serialization
插件或适配器
  • Asset Manager
  • Storage Manager
  • Rich Text Editor
  • Export

其中五个是你的。其余的已经存在,剩下的两个是配置而非施工。

第一步

在Vue 3中安装GrapesJS

一个依赖。GrapesJS 发布了自己的 TypeScript 定义,因此没有单独的 @types 包需要添加。

npm install grapesjs

导入样式表

没有样式表,编辑器是无样式的。在Vite或Nuxt项目中,你可以从创建编辑器的组件或组合器导入;而在有全局样式表的应用中,只需导入一次。

集成需求

  • 画布的DOM元素,通过模板参考访问
  • grapesjs.init() 在该元素之后被调用
  • 当元件消失时,editor.destroy() 会呼叫
  • GrapesJS 样式表加载在某处
  • 仅浏览器执行——详见 Nuxt 部分
第二步

一个极简可行的 Vue 3 示例

把它复制到组件中,它就能运行。本节之后的内容都是对它的补充,而不是重写。

可视化编辑器.vueVUE
<template>
  <div ref="editorContainer" class="editor-shell"></div>
</template>

<script setup lang="ts">
import { onMounted, onUnmounted, shallowRef, ref } from 'vue';
import grapesjs, { type Editor } from 'grapesjs';
import 'grapesjs/dist/css/grapes.min.css';

// A template ref: the name matches the ref="" attribute above.
const editorContainer = ref<HTMLDivElement | null>(null);

// shallowRef, not ref — see "Performance" further down the page.
const editor = shallowRef<Editor | null>(null);

onMounted(() => {
  if (!editorContainer.value) return;

  editor.value = grapesjs.init({
    container: editorContainer.value,
    height: '100%',
    fromElement: false,
    storageManager: false,
  });
});

onUnmounted(() => {
  editor.value?.destroy();
  editor.value = null;
});
</script>

<style scoped>
.editor-shell {
  height: 100vh;
}
</style>

有三件事值得注意

  1. 模板的ref名称与ref=“”属性匹配——这就是Vue在<script setup>中绑定它们的方式。

  2. 编辑器存在于 shallowRef,而非 ref。否则 Vue 会走遍整个编辑器对象图,使其变得被动。

  3. fromElement 是假的,所以 GrapesJS 是从你通过的组件开始的,而不是容器内部的标记。

生命周期

GrapesJS 与 Vue 3 Composition API 一起

整个积分是一个生命周期映射。Vue 告诉你 DOM 节点何时存在,何时即将消失;GrapesJS 正好需要这两个时刻。

VueGrapesJS
onMounted()
grapesjs.init()
容器元素现在存在,且仅限于此时。提前初始化使GrapesJS得到一个空容器。
onUnmounted()
editor.destroy()
移除监听器、canvas iframe 和编辑器 DOM 。跳过它会在每次路径变更时漏水。
ref()
容器元素
模板参考是GrapesJS挂载时所对应的handle。
shallowRef()
编辑器实例
保持实例状态,但不会让它变得非常反应性。

从头到尾读,这就是两个图书馆之间的全部合同。

onMounted和onUnmounted都不在服务器上运行,这也是为什么普通的Vue SPA不需要额外保护。服务器渲染的应用需要多一个保护——Nuxt部分涵盖了这一点。

可重复使用

创建一个可重复使用的 useGrapesJS 组合文件

一旦第二个屏幕需要编辑器,就把生命周期迁移到可组合界面。组件才会说它想要什么,而不是编辑器的连接方式。

useGrapesJS.tsTS
// composables/useGrapesJS.ts
import { onMounted, onUnmounted, shallowRef, type Ref } from 'vue';
import grapesjs, { type Editor, type EditorConfig } from 'grapesjs';
import 'grapesjs/dist/css/grapes.min.css';

type EditorOptions = Omit<EditorConfig, 'container'>;

export function useGrapesJS(
  container: Ref<HTMLElement | null>,
  options: EditorOptions = {},
) {
  const editor = shallowRef<Editor | null>(null);

  const init = (): Editor | undefined => {
    if (editor.value || !container.value) return;

    editor.value = grapesjs.init({
      container: container.value,
      height: '100%',
      fromElement: false,
      storageManager: false,
      ...options,
    });

    return editor.value;
  };

  const destroy = (): void => {
    editor.value?.destroy();
    editor.value = null;
  };

  onMounted(init);
  onUnmounted(destroy);

  return { editor, init, destroy };
}

使用

EditorScreen.vueVUE
<template>
  <div ref="editorContainer" class="editor-shell"></div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { useGrapesJS } from '~/composables/useGrapesJS';

const editorContainer = ref<HTMLElement | null>(null);

const { editor } = useGrapesJS(editorContainer, {
  blockManager: {
    blocks: [
      {
        id: 'hero',
        label: 'Hero',
        category: 'Sections',
        content: '<section>…</section>',
      },
    ],
  },
});
</script>

可组合设备能为你带来什么

  • 需要维护一个集成,而不是每个屏幕一个
  • 单一配置
  • 可以单独测试的编辑器设置
  • 一个应用中包含多个编辑器,无需复制粘贴
  • 事件处理在各个组件间共享
  • 这些元件读起来像Vue,而不是DOM管道

不要让它过度扩张。一个将每个GrapesJS模块包裹在反应式界面的组合文件,既是第二个需要学习的API,也是保持同步的第二个关键。

反应性

将GrapesJS事件与Vue连接

GrapesJS 管理编辑器状态。Vue 管理应用状态。事件是接缝:订阅少数几个你的 UI 实际反映的事件,然后写入普通参考。

editor-events.tsTS
import { onMounted, ref, shallowRef } from 'vue';
import type { Editor, Component } from 'grapesjs';

const isReady = ref(false);
const isDirty = ref(false);
const saveState = ref<'idle' | 'saving' | 'saved' | 'error'>('idle');
const selectedName = ref<string | null>(null);

function bindEditorEvents(editor: Editor): void {
  editor.on('load', () => {
    isReady.value = true;
  });

  editor.on('component:selected', (component: Component) => {
    selectedName.value = component?.getName?.() ?? null;
  });

  editor.on('component:update', () => {
    isDirty.value = true;
  });

  editor.on('storage:start:store', () => {
    saveState.value = 'saving';
  });

  editor.on('storage:end:store', () => {
    saveState.value = 'saved';
    isDirty.value = false;
  });

  editor.on('storage:error', () => {
    saveState.value = 'error';
  });
}
事件你的界面对它的作用
load项目在画布上后隐藏加载状态
component:selected在你自己的工具栏中显示选中了哪个元素
component:update标记文档为脏,启用保存按钮
storage:start:store显示储蓄指示
storage:end:store节目得救,清除污点旗
storage:error用户可以采取行动的故障表层

镜像你显示的内容,而不是编辑器里的存储。把组件树复制到Vue存储会给你两个真实来源和一个同步错误。

Nuxt 与 SSR

使用GrapesJS配合Nuxt

GrapesJS 依赖浏览器的 DOM API,所以编辑器初始化应该只在浏览器上下文中进行。在 Nuxt 中,这意味着编辑器不出现在服务器渲染中——其他一切都是你已有的集成。

Pages/Editor.VueVUE
<!-- pages/editor.vue -->
<template>
  <ClientOnly>
    <VisualEditor />

    <template #fallback>
      <p class="editor-placeholder">Loading the editor…</p>
    </template>
  </ClientOnly>
</template>
components/VisualEditor.client.vueVUE
<!-- components/VisualEditor.client.vue -->
<template>
  <div ref="editorContainer" class="editor-shell"></div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { useGrapesJS } from '~/composables/useGrapesJS';

// Reached only in the browser: the .client suffix keeps this
// component out of the server render, and onMounted never runs
// on the server anyway.
const editorContainer = ref<HTMLElement | null>(null);
const { editor } = useGrapesJS(editorContainer);
</script>

两个正确选项

<ClientOnly>

把编辑器包裹在使用到的地方。备用槽给服务器一个可以渲染的东西,这样在水合前就不会有空白帧。

一个 .client 组件

Nuxt 自己的命名规范:文件名以 .client 结尾的组件只在浏览器中渲染。当编辑器在多个地方使用时非常有用。

两者都是有效的,并且可以组合。GrapesJS 都不是强制要求的——GrapesJS 要求的只是 init() 在文档存在的地方运行。

建筑

边界所在

SSR 渲染应用壳层。GrapesJS 运行在浏览器中。命名这个边界使得 Nuxt 集成变得可预测,而不是水合漏洞的根源。

  1. Nuxt 应用
  2. SSR / 应用壳
  3. 仅客户端可视化编辑器
  4. GrapesJS
  5. API / CMS / 数据库

编辑器界面不是你为SEO服务器渲染的页面——它是一个认证工具。它生成的页面是你渲染和索引的内容,这些都是纯HTML和CSS。

构建一个完整的Vue页面构建器
判决

你需要Vue封装GrapesJS吗?

不是。直接集成是使用GrapesJS的完整且受支持的方式,这正是本页示例所做的。封装器是一种便利,而非必需品。

方法介绍最佳权衡
直通GrapesJS最大控制你自己写了生命周期——大约十五行。
Vue 封装器/集成更偏向 Vue 的 API你和编辑器API之间的依赖,依赖别人的发布时间表。
自定义组合可复用应用集成这是你自己维护的——但这就是上面展示的文件,而且不会变得陈旧。

实际出版的内容

在采用任何东西之前,值得先核实一下,因为这个问题的搜索结果比他们描述的套餐还要早。

官方 React 包装
@grapesjs/react 2.0.0,MIT,由GrapesJS维护者发布。
官方 Vue 包装
没有。GrapesJS 项目不发布 Vue 软件包。
社区 Vue 软件包
vue-grapesjs 0.1.0 是一个第三方项目,最后发布于 2022-05-23,拥有 vue@^2.6.6 和 grapesjs@^0.14.55 系列——Vue 2 以及更早的 GrapesJS。

我对照了2026-09-02的npm注册表。如果你找到更新的Vue封装,先读它的peerDependencies:那个单一栏能告诉你它是否针对Vue 3和当前的GrapesJS。

对于今天的 Vue 3,上面的组合是封装器。它有二十多行,直接使用 GrapesJS API,且不会落后于你依赖的版本。

超越整合

用GrapesJS构建一个Vue页面构建器

挂载编辑器是在第一个下午。剩下的部分工作是用户信任的页面构建器,主要是对GrapesJS已经发布的模块进行配置。

  • Canvas

    可编辑表面及其设备宽度。

  • Components

    用户可以放置的类型,以及他们的特征。

  • Blocks

    他们拖拽的调色板。

  • Style Manager

    哪些 CSS 属性被暴露,以及暴露给谁。

  • Asset Manager

    图片和媒体,来自你的存储。

  • Storage Manager

    项目数据被加载和保存。

  • Commands

    有名称的动作,可以绑定到你自己的UI上。

  • Device Manager

    编辑和输出时的响应式断点。

  • Plugins

    以上所有产品都已包装好且可重复使用。

学习如何构建完整的Vue页面构建器
你能建造的东西

用GrapesJS和Vue能建造什么?

同一个编辑器核心,但配置不同。每个核心都是不同的块、不同的存储目标和不同的发布步骤。

输出

GrapesJS 存储和生成什么?

这三件事很容易混淆,但合并起来却成本高昂。第一天就把这些做对,才让文档一年后依然可以重新编辑。

项目数据

GrapesJS 项目的可编辑状态——页面、组件、样式、资源。用 editor.getProjectData() 读取,用 editor.loadProjectData() 恢复。这就是要持久保存的东西。

HTML

渲染出来的标记,来自editor.getHtml()。每次发布时重新生成。它是输出,不是源。

CSS

编辑器生成的样式,来自editor.getCss()。同样规则:生成的,不作为真实的来源存储。

  1. User edits
  2. GrapesJS project data
  3. Your API / database
  4. HTML + CSS
  5. Preview / publish

存储可编辑的项目数据。需要渲染或发布时生成HTML和CSS。

只保存渲染后的 HTML 是无法纠正的错误。你总可以从项目数据重新生成 HTML;但你无法可靠地从 HTML 恢复项目数据。

publish.tsTS
// Editable state — store this, it is what the editor reloads.
const projectData = editor.getProjectData();

// Rendered output — regenerate this whenever you publish.
const html = editor.getHtml();
const css = editor.getCss();

await fetch(`/api/projects/${projectId}/publish`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ projectData, html, css }),
});

// Sanitize `html` on the server before it is served to anyone.
持久性

在你的Vue应用中保存GrapesJS项目

GrapesJS 不在乎你的后端是什么。存储适配器是两个异步函数——一个返回项目数据,一个接受项目数据——所以编辑器会与你已有的 API 通信。

  1. Vue
  2. GrapesJS storage
  3. REST API
  4. Backend
  5. Database
storage.tsTS
import grapesjs, { type ProjectData } from 'grapesjs';

// Wherever your app keeps it — a route param, a prop, a store.
const projectId = props.projectId;

const editor = grapesjs.init({
  container: editorContainer.value!,
  fromElement: false,
  storageManager: {
    type: 'app-api',
    autosave: true,
    stepsBeforeSave: 10,
  },
  // Registered as a plugin so the adapter exists before
  // GrapesJS performs its first load.
  plugins: [
    (ed) => {
      ed.Storage.add('app-api', {
        async load(): Promise<ProjectData> {
          const res = await fetch(`/api/projects/${projectId}`);
          if (!res.ok) {
            throw new Error(`Load failed: ${res.status}`);
          }
          return await res.json();
        },

        async store(data: ProjectData) {
          const res = await fetch(`/api/projects/${projectId}`, {
            method: 'PUT',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ projectData: data }),
          });
          if (!res.ok) {
            throw new Error(`Save failed: ${res.status}`);
          }
        },
      });
    },
  ],
});

适配器涵盖的内容

load()
编辑器打开时获取项目。
store()
将项目数据发送到你的终端。
autosave
经过一定次数的调整后,通过stepsBeforeSave点火。
Project JSON
序列化状态——你版本的那个。
Versioning
将之前的有效载荷保留在服务器端以支持回滚。
Publishing
一个独立的端点负责渲染和净化输出。

通过插件数组注册适配器很重要:这保证了存储在 GrapesJS 进行首次加载前就已存在。

媒体

管理您的Vue应用中的资产

资产管理就像一个终端上的界面。把它指向你的,所有现有规则——认证、验证、配额、CDN——都会持续生效。

assets.tsTS
// Fetched from your own API before the editor is created.
const assets = await fetch('/api/assets').then((res) => res.json());

const editor = grapesjs.init({
  container: editorContainer.value!,
  assetManager: {
    assets,

    // Uploads go to your endpoint, with your auth and
    // your validation.
    upload: '/api/assets',
    uploadName: 'files',
    multiUpload: true,
    autoAdd: true,
    headers: { Authorization: `Bearer ${token.value}` },
    credentials: 'same-origin',

    // Reject what the backend would reject anyway,
    // before the round trip.
    beforeUpload: (files: File[]) => {
      const limit = 5 * 1024 * 1024;
      const tooBig = files.some((f) => f.size > limit);
      if (tooBig) {
        toast.error('Images must be under 5 MB');
        return false;
      }
    },
  },
});
upload
你的端点;uploadName 是它发布的表单字段。
assets
给管理器添加API已知的URL。
headers / credentials
每次上传都会发送,这样你现有的认证就会持续生效。
beforeUpload
客户端拒绝;你的服务器仍然会验证。
Storage & CDN
GrapesJS 从不看到字节落在哪里——它存储的是你返回的 URL。
Asset URLs
最终会被发布在HTML中的内容,所以从持久的起点来提供它们。
你的词汇量

为Vue应用创建定制GrapesJS组件

自定义组件类型是编辑器学习你的产品的方式。它有自己的设置面板、自己的下落规则和调色板中的独立块。

pricing-card.tsTS
import type { Editor } from 'grapesjs';

export function pricingCardPlugin(editor: Editor): void {
  editor.Components.addType('pricing-card', {
    isComponent: (el) => el.dataset?.gjsType === 'pricing-card',
    model: {
      defaults: {
        tagName: 'section',
        attributes: { 'data-gjs-type': 'pricing-card' },
        // Traits become the settings panel for this component.
        traits: [
          { type: 'text', name: 'plan', label: 'Plan name' },
          { type: 'text', name: 'price', label: 'Price' },
          { type: 'checkbox', name: 'featured', label: 'Featured' },
        ],
        components: `
          <h3 data-gjs-type="text">Starter</h3>
          <p data-gjs-type="text">$0 / month</p>
          <a href="#">Choose plan</a>
        `,
      },
    },
  });

  editor.Blocks.add('pricing-card', {
    label: 'Pricing card',
    category: 'Marketing',
    content: { type: 'pricing-card' },
  });
}

// Pass it to the editor like any other plugin:
// grapesjs.init({ container, plugins: [pricingCardPlugin] })

典型的前五人组

  • Hero
  • Pricing card
  • Product card
  • Form
  • Navigation

自定义组件也是限制编辑器的方式。在类型上设置可丢弃或拖拽,是防止用户在导航栏内放置定价卡的关键,而特征则是给用户一个带标签的字段,而不是原始的CSS控件。

这些是 GrapesJS 组件类型,不是 Vue 组件。画布渲染 DOM;你的 Vue 组件渲染你的应用围绕它。

生态系统

用GrapesJS插件扩展你的Vue编辑器

插件是一个接收编辑器的函数——无论它来自npm、GJS.Market还是你自己的仓库,都是相同的函数签名。它们都不在乎主机应用是Vue。

plugins.tsTS
import grapesjs from 'grapesjs';
import basicBlocks from 'grapesjs-blocks-basic';
import { pricingCardPlugin } from '~/editor/pricing-card';

const editor = grapesjs.init({
  container: editorContainer.value!,
  plugins: [
    // Options go through a wrapper function: `pluginsOpts`
    // is keyed by string, so it only reaches plugins that
    // were passed to `plugins` by name.
    (ed) => basicBlocks(ed, { flexGrid: true }),
    pricingCardPlugin,
  ],
});

建造与采用

自己做可视化编辑器还是用GrapesJS?

这不是说建筑是错的——而是对建筑含义的清单。每一行都是一个子系统,无论你是否计划好。

能力打造自己GrapesJS
Canvas建造收录
Drag & drop建造收录
Components建造收录
Blocks建造收录
Style Manager建造收录
Asset Manager建造可扩展性
Storage Manager建造可扩展性
Plugins构建生态系统插件架构
Vue integration本地框架无关性

Vue 提供应用框架。GrapesJS 提供视觉编辑引擎。

为什么不完全用Vue组件来构建编辑器呢?

因为Vue组件是应用的构建模块,而可视化编辑器还需要在上面加点别的东西:画布管理、带有丢弃规则、选择和悬停状态的组件树、写真实CSS的样式层、设备切换、撤销和重做、资产管理、序列化、命名命令,以及整个项目的扩展点。你可以在Vue里构建这些——这只是一个和你最初想做的项目不同的项目。

Vue + GrapesJS 与单纯 Vue 组分是不同的命题。

制作阶段

GrapesJS + Vue 的生产架构

编辑器如何嵌入真实应用中,一旦有用户、权限和多个项目。
  1. Vue / Nuxt

    你的Nuxt或Vue应用程序:壳体、会话,以及谁被允许打开哪个项目。

    • Application UI
    • Authentication
    • Users
    • Permissions
  2. GrapesJS

    编辑器安装在一个屏幕上。它接收一个项目并发出一个项目。

    • Canvas
    • Components
    • Blocks
    • Styles
    • Assets
  3. Application API

    你自己的路由。GrapesJS 通过你写的存储和资产适配器调用它们。

  4. Backend

    项目、媒体、用户和版本实际上存在——不被上方编辑器更改。

    • Projects
    • Assets
    • Users
    • Versions

编辑器是那棵树上的一个叶子,不是根节点。它上面的所有内容都是你本来就会写的代码。

性能

性能考虑

  • 不要让编辑变得非常被动

    这才是真正会咬人的。shallowRef,或者一个普通的模块作用域变量——绝不会在编辑器实例周围使用ref()。Vue会走动一个非常大的对象图,并对内部流失执行效果。

  • 只有在需要时才初始化

    在编辑界面创建编辑器,而不是在每个路由都挂载的布局或存储中。

  • 懒惰加载编辑器

    GrapesJS 是一个相当可观的捆绑包。把它加载成独立的异步区块,这样那些从未编辑的路由就不会付费。

  • 将更新排除在全局状态之外

    将每个 component:update 推入存储,都会将每个按键都转化为应用范围的渲染。

  • 大型资产收藏的分页

    从分页端点为资产管理器做种子,而不是把成千上万的 URL 发送到编辑器里。

  • 保持组件树的管理

    非常深的文档渲染、序列化和差异化成本更高。如果你的块能做到,结构自然会促进。

安全性

安全考量

可视化编辑器是一个接受用户自撰HTML的系统。就这样对待它吧。

净化已发布的 HTML
在发布时,在服务器上进行净化处理,然后再向访客提供任何内容。
验证上传内容
类型、规模和内容——客户端检查是用户体验,而非强制执行。
认证存储端点
加载和保存是普通的API路由,需要普通的授权。
服务器端强制执行权限
在编辑器中隐藏面板不是一种授权模式。
验证项目数据
它是客户寄来的,可以是任何东西。存放前一定要检查一下。
永远不要信任编辑状态
浏览器关于编辑内容的任何信息都是主张,而非事实。
保护发布端点
出版改变了公众所看到的内容;限制并相应授权。
故障排除

常见的GrapesJS + Vue错误

几乎所有关于该组合的集成问题都属于这七个。

安装前初始化

症状

容器是空的,或者编辑器渲染成虚无。

修复

在onMounted()里创建编辑器。模板参考之前没有元素。

忘记清理

症状

记忆会增长,听众在离开路线后会开枪。

修复

用onUnmounted()呼叫editor.destroy()并清除参考。

让整个编辑都变得非常被动反应

症状

编辑器感觉迟钝;Vue 开发工具卡顿。

修复

将实例保持在浅层Ref,或者完全不在Vue反应性中。

在SSR期间初始化GrapesJS

症状

文档未定义,或者编辑路径上的水合不匹配。

修复

渲染编辑器为仅客户端——<ClientOnly>、.client组件,或两者兼有。

编辑器状态与应用状态的混合

症状

两个真实来源,以及在导航中消失的编辑。

修复

让GrapesJS拥有项目;只镜像你UI显示的少数数值。

忘记了CSS导入

症状

编辑器能加载,但面板没有样式且无法使用。

修复

导入 grapesjs/dist/css/grapes.min.css,或者包含在你的全局样式表中。

复制过时的包装示例

症状

类型错误,或者基于Vue 2生命周期钩子构建的集成。

修复

在采用任何封装器之前,请先检查peerDependencies。几个流行的例子早于Vue 3。

在Vue 2上,相同的积分使用mounted()和beforeDestroy()代替onMounted()和onUnmounted();GrapesJS侧保持不变。新工作应针对Vue 3——本页所有内容均假设如此。

在你发货之前

Vue + GrapesJS 生产清单

顺序大致与本页介绍他们的顺序相符。

  1. 安装GrapesJS
  2. 挂载后初始化
  3. 下车时摧毁
  4. 导入GrapesJS CSS
  5. 处理SSR / 仅客户端执行
  6. 决定直接集成还是封装
  7. 在需要时创建可重复使用的组合工具
  8. 连接编辑器事件,你的UI反映
  9. 配置存储
  10. 配置资产
  11. 添加自定义组件
  12. 添加你的产品所需的插件
  13. 在服务器端实现权限
  14. 净化已发布内容
  15. 测试响应式编辑
  16. 测试生产版本
常见问题

GrapesJS 与 Vue:常见问题解答

我可以和Vue 3一起使用GrapesJS吗?

是的。GrapesJS 是一个与框架无关的库,渲染成 DOM 元素,所以它在 Vue 3 中无需适配器即可工作。在 onMounted() 中初始化它,然后在 onUnmounted() 中销毁它。

我如何在Vue中安装GrapesJS?

运行 npm 安装 grapesjs。该包包含自己的 TypeScript 定义。你还需要加载它的样式表,要么导入 grapesjs/dist/css/grapes.min.css,要么将其包含在全局 CSS 中。

我该如何在Vue 3中初始化GrapesJS?

在容器元素上创建一个模板ref,然后在onMounted()中调用grapesjs.init({ container: containerRef.value })。该元素在挂载前不存在,所以初始化任何一个元素后,GrapesJS就没有可渲染的对象。

我可以和Composition API一起使用GrapesJS吗?

是的,这是推荐的方法。onMounted() 和 onUnmounted() 直接映射到 grapesjs.init() 和 editor.destroy(),整个集成都装进一个可组合单元里。

我可以在 <script setup> 中使用 GrapesJS 吗?

是的。本页上的每个示例都使用 <script setup lang="ts">。用 ref() 声明的模板 ref 会自动绑定匹配的 ref=“” 属性。

GrapesJS和Nuxt兼容吗?

是的。集成方式和普通的 Vue 3 完全一样;唯一的新增是编辑器不出现在服务器渲染中,使用 <ClientOnly> 或 .client 组件。

GrapesJS 能和 Nuxt SSR 一起使用吗?

是的,编辑器是只渲染客户端的。GrapesJS 需要浏览器 DOM API,所以不能在服务器渲染时运行——但它生成的页面是纯 HTML 和 CSS,这些正是你服务器渲染和索引的内容。

我需要为GrapesJS加装Vue封装器吗?

没有。直接集成是一种完整的方法,这里的例子就是这样。GrapesJS 发布了官方的 React 封装器,但没有 Vue 的对应版本,所以任何 Vue 封装器在 npm 上都是社区项目——在采用前请查看其 Vue 和 GrapesJS 的同类范围。

我可以在 TypeScript 中使用 GrapesJS 吗?

是的。GrapesJS 在包里自带了 TypeScript 定义,所以编辑器类型和配置对象的类型没有额外的 @types 依赖。

我可以把GrapesJS项目保存到我的Vue后端吗?

是的。用 editor.Storage.add() 注册一个存储适配器,实现 load() 和 store()。这两个都是普通的异步函数,所以可以调用你已有的任何 API。

我可以用GrapesJS创建自定义组件吗?

是的。editor.Components.addType() 定义了一个带有自身特征和下落规则的组件类型,而 editor.Blocks.add() 则将其放入调色板。这就是编辑器学习你产品术语的方式。

我可以在Vue上使用GrapesJS插件吗?

是的。GrapesJS 插件是一个接收编辑器实例的函数,因此不受托管框架的影响。将插件传递到 grapesjs.init() 插件数组中。

我可以用GrapesJS做一个Vue页面构建器吗?

是的——这是常见的情况。挂载编辑器是最短的部分;剩下的就是围绕它配置块、存储、资源和权限。

用GrapesJS构建你的Vue可视化编辑器

将视觉编辑引擎集成到你的Vue或Nuxt应用中,保持对数据和输出的控制,并用产品所需的插件扩展编辑器。

用 Vue 3 构建你的应用。用 GrapesJS 添加视觉编辑。

继续阅读

相关指南