Decorators 装饰器

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.

内联和块级样式不是我们希望添加到编辑器中的唯一一种富文本样式。比如Facebook的评论输入框,给@和标签提供了蓝色背景高亮。

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

为了支持自定义富文本的灵活性,Draft提供了一个“decorator”系统。tweet的例子提供了一个执行中的decorator的在线实例。

复合装饰器

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.

decorator 的概念是基于扫描一个被给予的文本范围的ContentBlock的内容,它们应该匹配一个被定义的策略,然后,用一个指定的React渲染它们。

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

你可以使用CompositeDecorator类来定义你想要的decorator行为。这个类允许你提供多个DraftDecorator对象,并且将轮流在一个文本块中依照每个策略进行搜索。

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

装饰器被保存在EditorState记录中。当创建一个新的EditorState对象时,例如通过EditorState.createEmpty(),一个装饰器或许会被可选的提供。

Under the hood

When contents change in a Draft editor, the resultingEditorStateobject will evaluate the newContentStatewith 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 ourEditorState.

在底层

当Draft编辑器中的内容变化时,作为结果的EditorState对象会使用它的装饰器求得新的ContentState值,并且识别需要被装饰的范围。一个完整的块级,装饰器和行内样式的树将在这时形成,并且作为我们输出渲染的基础。

通过这种方式,我们可以始终确保内容的变化,使得装饰器和我们的EditorState同步渲染。

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

在“Tweet”编辑器的例子中,打个比方,我们使用一个CompositeDecorator来搜索@句柄字符串以及#标签的字符串:

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.

这种复合Decorator首先会扫描一个给定的文本块是否匹配@句柄,然后扫描其是否匹配#标签。

// 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, contentState) {
  findWithRegex(HANDLE_REGEX, contentBlock, callback);
}

function hashtagStrategy(contentBlock, callback, contentState) {
  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.

策略函数使用匹配文本范围的起始和终止的值,执行提供的回调。

装饰器组件

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.

对于你要装饰的文本范围,你必须定义一个React组件用来渲染它们。通常是具有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:

在我们现在的例子里,CompositeDecorator 对象命名了HandleSpanHashtagSpan作为装饰组件。这些只是基础的无状态组件:

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是通过渲染输出的。这样做是为了确保文本在被装饰的span内呈现。

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

你可以对link使用相同的方法,如我们的link示例中所示。

超越混合装饰器

The decorator object supplied to an EditorStateneed 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.

被提供给EditorState的Decorator对象仅需要匹配DraftDecoratorType流类型定义的期望,这意味着你能创建任何你期望的装饰器类,只要他们匹配期望类型——你不会被CompositeDecorator约束

设置新装饰器

Further, it is acceptable to set a new decoratorvalue on the EditorStateon the fly, during normal state propagation -- through immutable means, of course.

此外,在动态的EditorState上设置一个新decorator值是被允许的,当然,是通过正常状态的传播,通过不可变的方法。

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 nullto remove all decorations) and EditorState.set() to make use of the new decorator setting.

这意味着,在你的程序工作过程中,如果你的装饰器变成无效的或需要修改,你可以创建一个新的装饰器对象(或使用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 ContentStatefor this editorStatewill be re-evaluated with the new decorator, and @-handle decorations will no longer be present in the next render pass.

这个editorStateContentState将被新的装饰器重新执行,并且@句柄装饰将不再出现在下一个渲染通道。

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

同样的,由于不可变的对象上的数据持久化,这保持了内存的效率。

results matching ""

    No results matching ""