WordPress新的Gutenberg編輯器是一個完全使用現(xiàn)代前端技術(shù)打造的編輯器。WordPress4.7引入的Rest API就奠定了WordPress的野心,Gutenberg也基于此技術(shù)。從前端的大潮流來看,經(jīng)典編輯器使用的舊技術(shù)勢必會被歷史淘汰。
Gutenberg從目前的進展來看,它包含了Block、Format、Sidebar三個部分。由于Gutenberg的開發(fā)很少有中文原創(chuàng)教程或心得,因此我便在博客中做了一些分享。例如之前分享過Block模塊的創(chuàng)建方法: http://www.ydqwiac.cn/how-to-creat-custom-block-type-in-gutenberg.html
Format是什么
Format顧名思義就是格式,它是在Gutenberg編輯器中的格式化工具。如段落上方的“對齊”、“加粗”等按鈕:

Format創(chuàng)建方法官方文檔用ES5已經(jīng)寫得非常詳細了,我這里不再重復(fù)。今天主要想分享的是:如何在Format中添加一個跟隨已選文本的Popover,并在里面做相關(guān)的設(shè)置。例如做一個文本色彩選擇器:

特別需要注意的是:這樣的一個寫法并非是我憑空杜撰,WordPress官方其實是有示例的,本文參考并致敬了“超鏈接”這個Format。
編寫一個Format
PHP部分
PHP的部分和Block的創(chuàng)建方法基本是一致的:大致邏輯是注冊一個腳本,在Block編輯器的鉤子上將腳本引入。
<?php
function register_pandastudio_block_format_mark() {
wp_register_script(
'pandastudio-block-format-mark-js',
//根據(jù)實際位置引入文件
get_stylesheet_directory_uri().'/pandastudio_plugins/format_mark/block.build.js',
array( 'wp-rich-text' )
);
}
add_action( 'init', 'register_pandastudio_block_format_mark' );
function register_pandastudio_block_format_mark_enqueue_assets_editor() {
wp_enqueue_script( 'pandastudio-block-format-mark-js' );
}
add_action( 'enqueue_block_editor_assets', 'register_pandastudio_block_format_mark_enqueue_assets_editor' );
還可根據(jù)實際場景需要引入css文件,這里就不做示例了。引入js文件的時候注意一下編譯后的文件位置。
Javascript部分
在WordPress的官方文章中,F(xiàn)ormat的示例教程是一個使用ES5開發(fā)出來的教程,對于功能復(fù)雜的場景,編寫過程會變得異常繁瑣,而且不便于人類閱讀。因此本文中我將做一個ES Next的開發(fā)示例。
注冊 Format 的方法是提供在 wp.richText 里面的,引入后即可使用。注冊一個 Format 基本結(jié)構(gòu)是:
const {
registerFormatType,
} = wp.richText;
registerFormatType( 'pandastudio/mark', {
title: '標記',
tagName: 'span',
className: 'pandastudio-mark',
attributes: {
style: 'style',
block: 'inline-block'
},
edit(){
//...
}
} );
由于我們的目的是點擊按鈕后,彈出一個Popover,而Popover有一個“顯示”和“未顯示”的狀態(tài)需要存儲。通過修改數(shù)據(jù)來控制Popover的顯示。而這個狀態(tài)數(shù)據(jù)在Format中默認是沒有辦法存儲的!因此,我們必須將edit方法擴展一下:
...
edit: class markEdit extends Component {
constructor() {
super( ...arguments );
this.state = {
modal_visibility: false,
};
}
render() {
//...
}
}
...
現(xiàn)在,我們有了一個 state 來存儲狀態(tài),并且將 Popover 的顯示狀態(tài)存儲在了 modal_visibility 中。接下來我們需要:
- 當用戶選擇了文本之后,這個 Format 按鈕才可用,否則是灰色不可用狀態(tài)。因此創(chuàng)建了一個
words_selected方法來進行判斷 - 對于 Popover,需要定位,查看 Popover 的文檔說明可以注意到有一個叫做 anchorRect 的參數(shù),因此編寫一個
set_popover_rect方法來創(chuàng)建 anchorRect 并存儲到 state 中,并在 Popover 的參數(shù)中讀取它 - 在 Format 按鈕點擊后,修改 state 中的 modal_visibility 為 true 來顯示 popover,并同時讀取當前的選中位置來創(chuàng)建 anchorRect 給 Popover 定位
- 在點擊 Popover 的外部后,通過修改 state 中的 modal_visibility 為 false 來關(guān)閉Popover
const { getRectangleFromRange } = wp.dom;
const { RichTextToolbarButton } = wp.editor;
const { Popover } = wp.components;
const { Fragment } = wp.element;
...
edit: class markEdit extends Component {
constructor() {
super( ...arguments );
this.show_modal = this.show_modal.bind( this );
this.close_modal = this.close_modal.bind( this );
this.words_selected = this.words_selected.bind( this );
this.set_popover_rect = this.set_popover_rect.bind( this );
this.state = {
modal_visibility: false,
};
}
words_selected() {
const { value } = this.props;
return value.start !== value.end;
}
set_popover_rect() {
const selection = window.getSelection();
const range = selection.rangeCount > 0 ? selection.getRangeAt( 0 ) : null;
var rectangle = getRectangleFromRange( range );
this.setState( { popover_rect: rectangle } );
}
show_modal() {
this.setState( { modal_visibility: true } );
this.set_popover_rect();
}
close_modal() {
this.setState( { modal_visibility: false } );
}
render() {
let {
isActive
} = this.props;
return (
<Fragment>
<RichTextToolbarButton
icon='editor-code'
title="標記"
onClick={ this.show_modal }
isActive={ isActive }
isDisabled={ !this.words_selected() }
/>
{ this.state.modal_visibility && (
<Popover
anchorRect = { this.state.popover_rect }
position = "bottom center"
className = "pandastudio_mark_popover"
onClickOutside = { this.close_modal }
>
Popover內(nèi)容
</Popover>
)}
</Fragment>
);
}
}
...
需要注意的是,在set_popover_rect方法中使用到了另一個getRectangleFromRange方法,這個方法是 WordPress 在 wp.dom 中提供的,需要先引入。其他組件的引入我這里就不在多說了,詳見WordPress文檔即可。
這樣,一個 Format 和 Popover 融合的框架就完成了。當Popover彈出后需要操作的其他事情,就可以在Popover的內(nèi)容中去添加事件方法了。
總結(jié)
這個示例中,主要有兩個部分需要注意:
- 注冊 Format 的方法中 edit 參數(shù)需要擴展才可以存儲狀態(tài)數(shù)據(jù)
- Popover的定位方法使用了 wp.dom.getRectangleFromRange 并傳入了已選文本的位置參數(shù),這是難點。這個方法 WordPress 官方?jīng)]有文檔描述,我也不是憑空找到的,此處致敬了“超鏈接”的編寫方法
參考文獻
- WordPress Block編輯器手冊 – Introduction to the Format API
- WordPress Block編輯器手冊 – Popover
- WordPress Gutenberg Github
注:本文原創(chuàng)出自 http://panda.panda-studio.cn/how-to-creat-custom-format-type-in-gutenberg ,轉(zhuǎn)載請注明該出處!





