4.Draftjs 学习笔记-Decorators

来源:互联网 发布:1980西安坐标系数据 编辑:程序博客网 时间:2024/05/16 02:59

本节重点就是策略渲染组件


Inline and block styles aren’t the only kind of rich styling that we might want to add to our editor. The Facebook comment input, for example, provides blue background highlights for mentions and hashtags.

除了内联与块样式,还有更多丰富的需求,比如评论里面的提及@

To support flexibility for custom rich text, Draft provides a “decorator” system. The tweet example offers a live example of decorators in action.

为了实现自定义富文本的灵活性,Draft 提供了一种“装饰器”系统。

CompositeDecorator | 复合装饰器

The decorator concept is based on scanning the contents of a given ContentBlock for ranges of text that match a defined strategy, then rendering them with a specified React component.

装饰器的原理,先根据策略(strategy)扫描内容块(ContentBlock),然后使用指定的组件渲染。

You can use the CompositeDecorator class to define your desired decorator behavior. This class allows you to supply multiple DraftDecorator objects, and will search through a block of text with each strategy in turn.

你可以使用CompositeDecorator 类定义装饰器行为。这个类允许使用多个装饰器对象,依次使用这些策略搜索内容块。

Decorators are stored within the EditorState record. When creating a new EditorState object, e.g. via EditorState.createEmpty(), a decorator may optionally be provided.

装饰器存储在EditorState内。当使用EditorState.createEmpty(),实例化一个EditorState对象,装饰器可以作为初始化参数。

Under the hood | 高级选项
When contents change in a Draft editor, the resulting EditorState object will evaluate the new ContentState with its decorator, and identify ranges to be decorated. A complete tree of blocks, decorators, and inline styles is formed at this time, and serves as the basis for our rendered output.
In this way, we always ensure that as contents change, rendered decorations are in sync with our EditorState.
大意就是装饰器是随内容编辑同步执行装饰的

In the “Tweet” editor example, for instance, we use a CompositeDecorator that searches for @-handle strings as well as hashtag strings:

以tweet 为例就是搜索@ 字符串和 # hash标签

const compositeDecorator = new CompositeDecorator([  {    strategy: handleStrategy,    component: HandleSpan,  },  {    strategy: hashtagStrategy,    component: HashtagSpan,  },]);

This composite decorator will first scan a given block of text for @-handle matches, then for hashtag matches.

首先执行@ 匹配策略,然后是标签匹配

// Note: these aren't very good regexes, don't use them!const HANDLE_REGEX = /\@[\w]+/g;const HASHTAG_REGEX = /\#[\w\u0590-\u05ff]+/g;function handleStrategy(contentBlock, callback) {  findWithRegex(HANDLE_REGEX, contentBlock, callback);}function hashtagStrategy(contentBlock, callback) {  findWithRegex(HASHTAG_REGEX, contentBlock, callback);}function findWithRegex(regex, contentBlock, callback) {  const text = contentBlock.getText();  let matchArr, start;  while ((matchArr = regex.exec(text)) !== null) {    start = matchArr.index;    callback(start, start + matchArr[0].length);  }}

The strategy functions execute the provided callback with the start and end values of the matching range of text.

策略函数的回调函数有匹配区域的起始值。

Decorator Components | 装饰组件

For your decorated ranges of text, you must define a React component to use to render them. These tend to be simple span elements with CSS classes or styles applied to them.

对于所要修饰的文本区域,必须定义一个组件渲染它们。通常是简单的带有css 类span来包裹。

In our current example, the CompositeDecorator object names HandleSpan and HashtagSpan as the components to use for decoration. These are just basic stateless components:

下面就是个复合装饰对象使用的无状态组件声明方式定义组件的实例

const HandleSpan = (props) => {  return <span {...props} style={styles.handle}>{props.children}</span>;};const HashtagSpan = (props) => {  return <span {...props} style={styles.hashtag}>{props.children}</span>;};Note

that props.children is passed through to the rendered output. This is done to ensure that the text is rendered within the decorated span.

props.children 确保渲染内容是所要装饰的范围内

You can use the same approach for links, as demonstrated in our link example.

参考上一篇中的代码实例

Beyond CompositeDecorator| 不局限于CompositeDecorator

The decorator object supplied to an EditorState need only match the expectations of the DraftDecoratorType Flow type definition, which means that you can create any decorator classes you wish, as long as they match the expected type – you are not bound by CompositeDecorator.

装饰器只要符合DraftDecoratorType 的类型定义,就可以创建任意类型的装饰器而不必使用CompositeDecorator包裹。

Setting new decorators| 动态修改decorators

Further, it is acceptable to set a new decorator value on the EditorState on the fly, during normal state propagation – through immutable means, of course.

进一步讲,在一般state 传递过程中可以设置EditorState中新的decorator,当然使用的immutable 方式。

This means that during your app workflow, if your decorator becomes invalid or requires a modification, you can create a new decorator object (or use null to remove all decorations) and EditorState.set() to make use of the new decorator setting.

这意味着,在应用流程中,当之前的decorator不能用了,或需要更改时,你可以创建个新的(或使用null去除所有装饰器),通过EditorState.set() 生效

For example, if for some reason we wished to disable the creation of @-handle decorations while the user interacts with the editor, it would be fine to do the following:

例如,当用户交互时我们去除@装饰器效果,代码如下:

function turnOffHandleDecorations(editorState) {  const onlyHashtags = new CompositeDecorator([{    strategy: hashtagStrategy,    component: HashtagSpan,  }]);  return EditorState.set(editorState, {decorator: onlyHashtags});}

The ContentState for this editorState will be re-evaluated with the new decorator, and @-handle decorations will no longer be present in the next render pass.

editorState 中的ContentState将使用新的装饰器重新渲染,@-handle装饰效果在下次渲染中实效。

Again, this remains memory-efficient due to data persistence across immutable objects.

还有就是因为是immutable所以内存还是很高效。

动手实践

代码以上篇为例,系列结束时,样例托管在github上。

2 0