前段時間我一直在設計和研究低程式碼搭建平臺,也開源了幾款視覺化編輯器框架,最近在 github 上發現了一款非常強大的基於自然流佈局的頁面搭建框架 GrapesJS,接下來我就帶大家摸索一下這款框架。
按照我一向的寫作風格,我會在下面列出文章的大綱,以便大家有選擇且高效率的閱讀和學習:
-
GrapesJS 框架基本介紹
-
如何使用 GrapesJS 構建 web 編輯器
-
基於 GrapesJS 構建的開源網頁編輯器 craft.js
-
更多視覺化編輯器推薦
基本介紹
乍眼一看我們可能會認為它只是一個頁面/HTML 編輯器,但它能做的不僅僅如此。GrapesJS 是一個多用途的 Web 頁面搭建框架,這意味著它允許我們輕鬆建立一個支援拖放的任何具有類似 HTML 結構的構建器。它所包含的內容遠不止網頁。我們使用類似 HTML 的結構的場景有:
- 時事通訊(例如 MJML)
- 原生移動應用程式(例如 React Native)
- 本機桌面應用程式(例如 Vuido)
- PDF (例如 React PDF)
並且 GrapesJS 附帶的功能和工具使我們能夠製作易於使用的編輯器。這使使用者無需任何編碼知識即可建立複雜的類似 HTML 的模板。
同時 GrapesJS 官網上還給我們提供了3個不同場景的案例, 我們可以參考這些案例快速製作屬於我們自己的web編輯器:
那麼至於這些搭建框架的實現原理, 我之前的文章中也做了很多剖析和設計, 大家如果感興趣可以參考研究一下, 接下來我們看看如何安裝和使用它.
如何使用 GrapesJS 構建 web 編輯器
1. 安裝
我們可以用 umd
的方式來匯入:
<link rel="stylesheet" href="//unpkg.com/grapesjs/dist/css/grapes.min.css">
<script src="//unpkg.com/grapesjs"></script>
複製程式碼
也可以通過 npm
來安裝:
npm i grapesjs -S
複製程式碼
之後我們可以通過如下方式匯入到專案:
import 'grapesjs/dist/css/grapes.min.css';
import grapesjs from 'grapesjs';
複製程式碼
2. 第一個demo
在安裝完之後, 我們先實現一個基本的頁面編輯demo:
相關程式碼如下:
<html>
<head>
<link rel="stylesheet" href="//unpkg.com/grapesjs/dist/css/grapes.min.css">
<script src="//unpkg.com/grapesjs"></script>
<style>
#gjs {
border: 3px solid #444;
}
.gjs-cv-canvas {
top: 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="gjs">
<h1>Hello World Component!</h1>
</div>
<script>
const editor = grapesjs.init({
container: '#gjs',
// 我們也可以使用可選的: `components: '<h1>Hello World Component!</h1>'`,
fromElement: true,
// 編輯器尺寸
height: '300px',
width: 'auto',
// 禁用儲存管理, 下面的文章我會介紹
storageManager: false,
panels: { defaults: [] },
});
</script>
</body>
</html>
複製程式碼
這樣就實現了一個簡單的編輯器, 是不是很簡單呢? 我們接下來繼續探索更強大的功能。
3. 新增和定義元件
我們都知道網頁編輯器需要提供非常豐富的元件, 這樣能幫助使用者更輕鬆的搭建頁面, 同樣 grapesjs 支援新增各種自定義元件, 也內建了常用的基礎元件, 我們來看一個 demo :
由以上 demo
我們可以看到新增了3個基本元件: 區塊, 文字, 圖片。基本實現程式碼如下:
const editor = grapesjs.init({
// ...其他配置
blockManager: {
appendTo: '#blocks',
blocks: [
{
id: 'section',
label: '<b>Section</b>',
attributes: { class:'gjs-block-section' },
content: `<section>
<h1>H5-Dooring</h1>
<div>積木式搭建H5頁面</div>
</section>`,
}, {
id: 'text',
label: 'Text',
content: '<div data-gjs-type="text">My Baby</div>',
}, {
id: 'image',
label: 'Image',
select: true,
content: { type: 'image' },
activate: true,
}
]
},
});
複製程式碼
由程式碼我們可以發現我們只需要在 blockManager
的 blocks
裡新增指定的元件即可。同時我們還可以動態的新增元件:
editor.BlockManager.add('my-block-id', {
// ...其他配置如label
content: {
tagName: 'div',
draggable: false,
attributes: { 'some-attribute': 'some-value' },
components: [
{
tagName: 'span',
content: '<b>DooringX</b>',
}, {
tagName: 'div',
components: '<span>無限可能</span>',
}
]
}
})
複製程式碼
至於更詳細的元件配置文件, 大家可以參考文件: grapesjs元件如何工作
4. 新增功能皮膚
僅僅實現元件新增還不夠, 一個有尊嚴的編輯器還應該有各種功能按鈕, 來實現不同使用者的需求。
現在我們有了畫布和自定義元件,讓我們看看如何建立一個功能皮膚,裡面有按鈕(使用Panels API)。
我們可以看到頂部有3個功能按鈕:
- 是否顯示元件邊線
- 顯示原始碼
- 顯示json
首先我們需要定義用來展示功能皮膚的元素(樣式可以自定義):
<div class="panel__top">
<div class="panel__basic-actions"></div>
</div>
複製程式碼
其次我們來定義掛載功能皮膚:
editor.Panels.addPanel({
id: 'panel-top',
el: '.panel__top',
});
editor.Panels.addPanel({
id: 'basic-actions',
el: '.panel__basic-actions',
buttons: [
{
id: 'visibility',
active: true,
className: 'btn-toggle-borders',
label: '<u>B</u>',
command: 'sw-visibility',
}, {
id: 'export',
className: 'btn-open-export',
label: 'Exp',
command: 'export-template',
context: 'export-template',
}, {
id: 'show-json',
className: 'btn-show-json',
label: 'JSON',
context: 'show-json',
command(editor) {
editor.Modal.setTitle('Components JSON')
.setContent(`<textarea style="width:100%; height: 250px;">
${JSON.stringify(editor.getComponents())}
</textarea>`)
.open();
},
}
],
});
複製程式碼
我們可以定義更多的功能, 大家可以參考文件來學習使用。
5. 新增圖層管理皮膚
在處理 Web
元素時,我們可能會發現另一個常見的工具是圖層管理器。它是樹狀結構的,使我們能夠輕鬆地對頁面元素進行管理。要啟用它,我們只需指定要渲染它的位置:
const editor = grapesjs.init({
// ...
layerManager: {
appendTo: '.layers-container'
},
// 我們能定義一個預設的皮膚作為側邊圖層管理器
panels: {
defaults: [{
id: 'layers',
el: '.panel__right',
// 定義皮膚能否拖拽
resizable: {
maxDim: 350,
minDim: 200,
tc: 0,
cl: 1, // 左側可拖拽
cr: 0,
bc: 0,
keyWidth: 'flex-basis',
},
}]
}
});
複製程式碼
效果如下:
我們可以看到右側的圖層皮膚, 可以輕鬆管理我們頁面上的元素。
6. 新增樣式配置皮膚
樣式皮膚也很簡單, 我們先定義對應的容器:
<div class="panel__right">
<div class="layers-container"></div>
<div class="styles-container"></div>
</div>
複製程式碼
然後初始化對應的配置指令碼:
const editor = grapesjs.init({
// ...
panels: {
defaults: [
// ...
{
id: 'panel-switcher',
el: '.panel__switcher',
buttons: [{
id: 'show-layers',
active: true,
label: 'Layers',
command: 'show-layers',
// Once activated disable the possibility to turn it off
togglable: false,
}, {
id: 'show-style',
active: true,
label: 'Styles',
command: 'show-styles',
togglable: false,
}],
}
]
},
selectorManager: {
appendTo: '.styles-container'
},
styleManager: {
appendTo: '.styles-container',
sectors: [{
name: 'Dimension',
open: false,
buildProps: ['width', 'min-height', 'padding'],
properties: [
{
type: 'integer',
name: 'The width',
property: 'width',
units: ['px', '%'],
defaults: 'auto',
min: 0,
}
]
},{
name: 'Extra',
open: false,
buildProps: ['background-color', 'box-shadow', 'custom-prop'],
properties: [
{
id: 'custom-prop',
name: 'Custom Label',
property: 'font-size',
type: 'select',
defaults: '32px',
options: [
{ value: '12px', name: 'Tiny' },
{ value: '18px', name: 'Medium' },
{ value: '32px', name: 'Big' },
],
}
]
}]
},
});
// 定義指令
editor.Commands.add('show-layers', {
getRowEl(editor) { return editor.getContainer().closest('.editor-row'); },
getLayersEl(row) { return row.querySelector('.layers-container') },
run(editor, sender) {
const lmEl = this.getLayersEl(this.getRowEl(editor));
lmEl.style.display = '';
},
stop(editor, sender) {
const lmEl = this.getLayersEl(this.getRowEl(editor));
lmEl.style.display = 'none';
},
});
editor.Commands.add('show-styles', {
getRowEl(editor) { return editor.getContainer().closest('.editor-row'); },
getStyleEl(row) { return row.querySelector('.styles-container') },
run(editor, sender) {
const smEl = this.getStyleEl(this.getRowEl(editor));
smEl.style.display = '';
},
stop(editor, sender) {
const smEl = this.getStyleEl(this.getRowEl(editor));
smEl.style.display = 'none';
},
});
複製程式碼
我們可以看看配置後的效果:
7. 更多用法演示
除了以上介紹的功能, 我們還能實現:
- 定義響應模式(pc, 移動, ipad),
- 設定儲存和載入資料的模式
- 自定義主題
- 國際化 i18n 支援
這裡就不一一介紹了, 我們直接看一下配置後的演示效果:
基於 GrapesJS 構建的開源網頁編輯器 craft.js
那麼 GrapesJS 還有很多有意思的功能我們可以挖掘, 接下來我和大家分享一款基於GrapesJS 二次封裝的一個開源編輯器框架 craft.js。
我們可以使用它外掛化的搭建我們自己的編輯器, 如下是一個應用在React中的例子:
import {Editor, Frame, Canvas, Selector} from "@craftjs/core";
// 定義本文元件
import {useNode} from "@craftjs/core";
const TextComponent = ({text}) => {
const { connectors: {drag} } = useNode();
return (
<div ref={drag}>
<h2>{text}</h2>
</div>
)
}
// 初始化編輯器
const App = () => {
return (
<div>
<Editor>
// 可編輯的區域
<Frame resolver={TextComponent, Container}>
<Canvas>
<TextComponent text="趣談前端 - 徐小夕" />
</Canvas>
</Frame>
</Editor>
</div>
)
}
複製程式碼
更多視覺化編輯器推薦
- h5-Dooring | H5編輯器, 積木式搭建H5頁面
- v6.dooring | 視覺化大屏搭建解決方案
- craft | 基於React的拖拽頁面生成器
- dooringx-lib | 快速高效搭建視覺化拖拽平臺
最後
後期我會在資料視覺化和工程化上輸出更多實用的開源專案和框架,如果有其他問題或需求,可以和筆者交流學習。如果這篇文章對你有幫助,希望能給筆者 點贊+收藏 以此鼓勵作者繼續創作前端硬核文章。也可以關注作者公眾號 趣談前端 第一時間推送前端好文。