概述

自动补全器会在用户输入时显示建议。当在空格后或新行开始处输入触发字符(例如 ' :')时,会显示建议。按下 Escape 键将关闭自动补全器。

如何创建自定义自动补全器

添加自定义自动补全器的方法位于编辑器 API 的 UI Registry 部分 editor.ui.registry:

  • editor.ui.registry.addAutocompleter(name, options)

该方法接受的两个参数为:

  • name — 自动补全器的唯一名称。

  • options — 包含自定义自动补全器配置的对象。

选项

名称值要求描述

trigger

string

必填

触发自动补全器的字符串。

fetch

(pattern: string, maxResults: number, fetchOptions: Record<string, any>) => Promise<AutocompleteItem[] | CardMenuItem[]

必填

一个函数,接收当前匹配的文本模式、预期结果的最大数量以及任何额外的 fetch 选项。该函数应返回包含匹配结果的 Promise。

onAction

(api, rng: Range, value: string) => void

必填

当选中某个获取项时调用的函数。

columns

number 或 'auto'

可选

默认值:auto - 要显示的列数。如果设置为 1 列,则显示图标和文本,否则仅显示图标。

matches

(rng: Range, text: string, pattern: string) => boolean

可选

默认值:isStartOfWord - 一个条件(谓词)函数,接收一个范围、当前文本节点内容以及匹配的文本内容,返回一个布尔值,指示是否应触发自动补全器。

maxResults

number

可选

默认值:10 - 应获取的最大结果数量。

minChars

number

可选

默认值:1 - 在自动补全器触发之前必须输入的最小字符数(不包括触发字符)。

highlight

array

可选

当使用 CardMenuItem 时,使用 highlight 选项指定要在哪些 CardText 项上高亮匹配的文本模式。

如果两个或多个自动补全器使用相同的触发字符,那么获取的结果将在显示之前合并在一起。

fetch 的用法

当按下触发 char 并且 matches 谓词(条件函数)返回 true 时,会调用 fetch 函数。fetch 函数接收匹配的文本模式,并返回一个包含匹配结果的 Promise,这些结果可以是 AutocompleteItems 或 CardMenuItems。这允许异步获取项。传递给 fetch 函数的 fetchOptions 参数默认是一个空对象,但是使用 reload API,可以传递额外的选项以获取不同的结果集。

有两种类型的项:

  • AutocompleteItem

  • CardMenuItem

AutocompleteItem

这是自动补全器的标准项。如果未指定类型,则自动补全器项将被视为 AutocompleteItem 类型。

名称值要求描述

value

string

可选

项的值。当选中时,这将传递给 onAction 回调。

text

string

可选

要为项显示的文本。

icon

string

可选

要显示的图标名称。必须是一个单 Unicode 字符或来自以下来源的图标:图标包、自定义图标包,或使用 addIcon API 添加的图标。

{
  type: 'autocompleteitem',
  value: 'John Doe',
  text: 'John Doe',
  icon: 'my_icon'
}

CardMenuItem

CardMenuItem 允许自定义布局和内容。这是通过构建一个子组件规范数组来实现的,该数组将确定最终项的结构。一个经典的例子是,需要显示一个“用户”项,其中包含个人资料图片、用户名和描述。

名称值要求描述

items

array

必填

CardItems 的数组

value

string

可选

项的值。当选中时,这将传递给 onAction 回调。

label

string

optional

项目的标签。将用于 无障碍访问目的。

{
  type: 'cardmenuitem',
  value: 'John Doe',
  label: 'John Doe',
  items: [ ] // 卡片项数组
}

CardItems

CardItems 是 CardMenuItem 的子组件。使用这些组件来构建自定义项并向用户显示相关信息。

卡片项有三种类型:

  • CardContainer

  • CardText

  • CardImage

CardContainer

CardContainer 是一个布局组件,用于将布局应用于卡片项数组。

名称值要求描述

items

array

required

CardItems 数组

direction

'vertical' 或 'horizontal'

optional

默认值:horizontal - 子项的方向

align

'left' 或 'right'

optional

默认值:left - 子项的水平对齐方式

valign

'top'、'middle' 或 'bottom'

optional

默认值:middle - 子项的垂直对齐方式

{
  type: 'cardcontainer',
  direction: 'horizontal',
  align: 'left',
  valign: 'middle',
  items: [ ... ]
}
CardText

CardText 是一个用于显示文本的组件。

名称值要求描述

text

string

required

要显示的文本

name

string

optional

用于引用特定 CardText 项的标识符。自动补全器将使用此标识符来实现文本高亮功能。

classes

array

optional

要应用的类名数组。注意:仅使用不会影响布局的样式,例如 font-style。

{
  type: 'cardtext',
  text: 'John Doe',
  name: 'my_autocompleter_cardtext',
  classes: ['my-cardtext-class']
}
CardImage

CardImage 是一个用于显示图像的组件。

名称值要求描述

src

string

required

要使用的图像源

alt

string

required

图像的替代文本

classes

array

optional

要应用的类名数组。注意:仅使用不会影响布局的样式,例如 border-radius。

{
  type: 'cardimage',
  src: 'profile-picture.jpeg',
  alt: '我的替代文本',
  classes: ['my-cardimage-class']
}

API

名称值描述

hide

() => void

隐藏自动补全器菜单。

reload

(fetchOptions: Record<string, any>) => void

隐藏自动补全器菜单并获取新的菜单项。fetchOptions 将传递给自动补全器的 fetch 回调函数。

交互式示例

以下示例展示了如何创建特殊字符的自动补全器。

示例:标准自动补全器

此示例使用标准自动补全器项,当用户输入冒号(:)字符和至少一个额外字符时,将显示该补全器。

HTML

<textarea id="autocompleter-autocompleteitem">
  <p>在下方输入 <b>:</b> 然后继续输入以减少更多匹配项。例如,输入 <b>:amp</b> 应该会在菜单中显示 ampersand 项。按 esc 键应关闭自动补全菜单。</p>
  <p></p>
</textarea>

JS

const specialChars = [
  { text: 'exclamation mark', value: '!' },
  { text: 'at', value: '@' },
  { text: 'hash', value: '#' },
  { text: 'dollars', value: '$' },
  { text: 'percent sign', value: '%' },
  { text: 'caret', value: '^' },
  { text: 'ampersand', value: '&' },
  { text: 'asterisk', value: '*' }
];
tinymce.init({
  selector: 'textarea#autocompleter-autocompleteitem',
  height: 250,
  setup: (editor) => {
    const onAction = (autocompleteApi, rng, value) => {
      editor.selection.setRng(rng);
      editor.insertContent(value);
      autocompleteApi.hide();
    };

    const getMatchedChars = (pattern) => {
      return specialChars.filter((char) => char.text.indexOf(pattern) !== -1);
    };

    /* 一个允许插入特殊字符的自动补全器 */
    editor.ui.registry.addAutocompleter('specialchars', {
      trigger: ':',
      minChars: 1,
      columns: 'auto',
      onAction: onAction,
      fetch: (pattern) => {
        return new Promise((resolve) => {
          const results = getMatchedChars(pattern).map((char) => ({
            type: 'autocompleteitem',
            value: char.value,
            text: char.text,
            icon: char.value
          }));
          resolve(results);
        });
      }
    });
  }
});

示例:在 Autocompleter 中使用 CardMenuItems

此示例使用 CardMenuItems,当用户输入连字符 (-) 字符和至少一个附加字符时将显示。

HTML

<textarea id="autocompleter-cardmenuitem">
  <p>在下方输入<b>-</b>然后继续输入以减少匹配项。例如,输入<b>-amp</b>应会在菜单中显示 ampersand 项。按下 esc 应会关闭自动补全菜单。</p>
  <p></p>
</textarea>

JS

const specialChars = [
  { text: 'exclamation mark', value: '!' },
  { text: 'at', value: '@' },
  { text: 'hash', value: '#' },
  { text: 'dollars', value: '$' },
  { text: 'percent sign', value: '%' },
  { text: 'caret', value: '^' },
  { text: 'ampersand', value: '&' },
  { text: 'asterisk', value: '*' }
];
tinymce.init({
  selector: 'textarea#autocompleter-cardmenuitem',
  height: 250,
  setup: (editor) => {
    const onAction = (autocompleteApi, rng, value) => {
      editor.selection.setRng(rng);
      editor.insertContent(value);
      autocompleteApi.hide();
    };

    const getMatchedChars = (pattern) => {
      return specialChars.filter(char => char.text.indexOf(pattern) !== -1);
    };

    /**
     * 一个允许插入特殊字符的自动补全器。
     * 条目使用 CardMenuItem 构建。
     */
    editor.ui.registry.addAutocompleter('specialchars_cardmenuitems', {
      trigger: '-',
      minChars: 1,
      columns: 1,
      highlightOn: ['char_name'],
      onAction: onAction,
      fetch: (pattern) => {
        return new Promise((resolve) => {
          const results = getMatchedChars(pattern).map(char => ({
            type: 'cardmenuitem',
            value: char.value,
            label: char.text,
            items: [
              {
                type: 'cardcontainer',
                direction: 'vertical',
                items: [
                  {
                    type: 'cardtext',
                    text: char.text,
                    name: 'char_name'
                  },
                  {
                    type: 'cardtext',
                    text: char.value
                  }
                ]
              }
            ]
          }));
          resolve(results);
        });
      }
    });
  }
});