文本编辑器

Framework7 带有一个触控友好的富文本编辑器组件。它基于现代“contenteditable”API,因此应该可以在任何地方正常工作。

它带有基本格式设置功能。但其功能可以轻松扩展和定制,以满足任何要求。

文本编辑器布局

<div class="text-editor">
  <div class="text-editor-content" contenteditable></div>
</div>

为使编辑器可调节大小(当其高度与其内容相符时),我们需要为编辑器元素添加 text-editor-resizable

<!-- additional "text-editor-resizable" class -->
<div class="text-editor text-editor-resizable">
  <div class="text-editor-content" contenteditable></div>
</div>

文本编辑器应用方法

让我们了解相关的应用方法,以便使用文本编辑器

app.textEditor.create(parameters)- 创建文本编辑器实例

  • parameters - object。包含文本编辑器参数的对象

该方法将返回创建的文本编辑器实例

app.textEditor.destroy(el)- 销毁文本编辑器实例

  • el - HTMLElementstring(带 CSS 选择器)或 object。要销毁的文本编辑器元素或文本编辑器实例。

app.textEditor.get(el)- 根据 HTML 元素获取文本编辑器实例

  • el - HTMLElementstring(带 CSS 选择器)。文本编辑器元素。

该方法将返回文本编辑器的实例

例如

var textEditor = app.textEditor.create({
  el: '#my-text-editor',
  value: <code><p>Hello</p></code>,
});

文本编辑器参数

让我们查看所有可用的文本编辑器参数的列表

参数类型默认值说明
elHTMLElement
string
文本编辑器元素。HTMLElement 或带编辑器元素 CSS 选择器的字符串
valuestring

文本编辑器的初始 html 内容值。初始值还可以作为 text-editor-content 元素的内部 HTML 内容放置,例如

<div class="text-editor">
  <div class="text-editor-content" contenteditable>
    <p>Initial HTML value</p>
  </div>
</div>
placeholderstring当编辑器为空时显示的编辑器占位符内容。默认情况下未指定
modestringtoolbar

文本编辑器按钮模式。可以是

  • toolbar - 它将在文本编辑器容器元素中添加带编辑器按钮的工具栏
  • popover - 它将在编辑器中选定文本的顶部显示带编辑器按钮的弹出气泡
  • keyboard-toolbar - 当编辑器处于焦点时,带编辑器按钮的工具栏将出现在虚拟键盘的顶部。仅支持 iOS、Android cordova 应用和 Android Chrome。如果不支持,它将回退到 popover 模式。
buttonsarray

包含编辑器按钮的数组,或包含编辑器按钮的数组(组)的数组。默认情况下,所有按钮均已启用,其默认值为

[
  ['bold', 'italic', 'underline', 'strikeThrough'],
  ['orderedList', 'unorderedList'],
  ['link', 'image'],
  ['paragraph', 'h1', 'h2', 'h3'],
  ['alignLeft', 'alignCenter', 'alignRight', 'alignJustify'],
  ['subscript', 'superscript'],
  ['indent', 'outdent'],
]
dividersbooleantrue在按钮组之间添加可视分隔符
imageUrlTextstring插入图片 URL图片 URL 请求中显示的提示文本
linkUrlTextstring插入链接 URL链接 URL 请求中显示的提示文本
clearFormattingOnPastebooleantrue如果启用该功能,则它将清除从剪贴板粘贴的任何格式
customButtonsobject

包含自定义按钮的对象。对象属性键是应在 buttons 中用于启用它的按钮 ID。

例如,要指定添加 <hr> 的自定义按钮,我们可使用以下声明

var textEditor = app.textEditor.create({
  el: '.my-text-editor',
  customButtons: {
    // property key is the button id
    hr: {
      // button html content
      content: '&lt;hr&gt;',
      // button click handler
      onClick(event, buttonEl) {
        document.execCommand('insertHorizontalRule', false);
      }
    }
  },
  // now we use custom button id "hr" to add it to buttons
  buttons: ['bold', 'italic', 'hr']
})
已打开object

带事件处理程序的对象。例如

var textEditor = app.textEditor.create({
  ...
  on: {
    change: function () {
      console.log('Text Editor value changed')
    }
  }
})

请注意,所有以下参数可在 textEditor 属性下的全局应用参数中使用,以便设置所有文本编辑器的默认值。例如

var app = new Framework7({
  textEditor: {
    buttons: ['bold', 'italic'],
  }
});

文本编辑器方法和属性

在初始化文本编辑器后,我们在变量(如上面的示例中的 textEditor 变量)中有其初始化实例,其中包含有用的方法和属性

属性
textEditor.app到全局应用实例的链接
textEditor.el文本编辑器容器 HTML 元素
textEditor.$el具有文本编辑器容器 HTML 元素的 Dom7 实例
textEditor.contentEl文本编辑器内容(contenteditalbe)HTML 元素
textEditor.$contentEl具有文本编辑器内容(contenteditalbe)HTML 元素的 Dom7 实例
textEditor.value文本编辑器的 HTML 值
textEditor.params带初始化参数的对象
方法
textEditor.setValue(value)设置新的文本编辑器值。value 是 HTML 字符串。
textEditor.getValue()返回当前文本编辑器值
textEditor.clearValue()清除文本编辑器值
textEditor.getSelectionRange()返回当前选择范围
textEditor.setSelectionRange(range)根据传递的范围设置选择
textEditor.destroy()销毁文本编辑器实例并删除所有事件
textEditor.on(event, handler)添加事件处理程序
textEditor.once(event, handler)添加在触发后将被删除的事件处理程序
textEditor.off(event, handler)删除事件处理程序
textEditor.off(event)删除针对指定事件的所有处理程序
textEditor.emit(event, ...args)在实例上触发事件

文本编辑器事件

文本编辑器将在文本编辑器元素上触发以下 DOM 事件以及在应用和文本编辑器实例上触发事件

DOM 事件

事件说明
texteditor:init在编辑器初始化时触发事件
texteditor:change在编辑器值发生更改时触发事件
texteditor:input在编辑器的内容“input”事件上触发事件
texteditor:focus在编辑器的内容焦点上触发事件
texteditor:blur在编辑器的内容模糊上触发事件
texteditor:buttonclick在编辑器按钮单击上触发事件
texteditor:keyboardopen在编辑器键盘工具栏出现时触发事件
texteditor:keyboardclose在编辑器键盘工具栏消失时触发事件
texteditor:popoveropen在编辑器弹出框打开上触发事件
texteditor:popoverclose在编辑器弹出框关闭上触发事件
texteditor:beforedestroy文本编辑器实例即将销毁之前会触发此事件

应用和文本编辑器实例事件

文本编辑器实例在自身实例和应用实例上发出事件。应用实例事件有相同名称,前缀为“textEditor”。

事件目标参数说明
inittextEditor(editor)编辑器初始化后将触发此事件。
textEditorInit应用
changetextEditor(editor)编辑器初始化后将触发此事件。
textEditorChange应用
inputtextEditor(editor)编辑器内容“输入”事件后会触发此事件。
textEditorInput应用
focustextEditor(editor)编辑器内容获得焦点后会触发此事件。
textEditorFocus应用
blurtextEditor(editor)编辑器内容失去焦点后会触发此事件。
textEditorBlur应用
buttonClicktextEditor(editor, button)编辑器按钮单击后会触发此事件。
事件处理程序接收单击的按钮的 ID 作为第二个参数,例如“粗体”。
textEditorButtonClick应用
keyboardOpentextEditor(editor)编辑器键盘工具栏出现后会触发此事件。
textEditorKeyboardOpen应用
keyboardClosetextEditor(editor)编辑器键盘工具栏消失后会触发此事件。
textEditorKeyboardClose应用
popoverOpentextEditor(editor)编辑器弹出层打开后会触发此事件。
textEditorPopoverOpen应用
popoverClosetextEditor(editor)编辑器弹出层关闭后会触发此事件。
textEditorPopoverClose应用
beforeDestroytextEditor(editor)文本编辑器实例即将销毁之前会触发此事件。
textEditorBeforeDestroy应用

文本编辑器自动初始化

如果你不需要使用文本编辑器 API,并且你的文本编辑器位于页面中,并在页面初始化时显示在 DOM 中,那么可以通过仅仅添加一个额外的“text-editor-init”类来自动初始化它

<!-- Add text-editor-init class -->
<div class="text-editor text-editor-init">
  <div class="text-editor-content" contenteditable></div>
</div>

在这种情况下,如果你需要访问已创建的文本编辑器实例,可以使用“app.textEditor.get”应用方法

var textEditor = app.textEditor.get('.my-text-editor');

if (!textEditor.value) {
  // do something
}

在使用自动初始化时,可能需要传递其他参数。这可以通过面板元素上的“data-”属性来完成。

<!-- parameters set via data- attributes -->
<div
  class="text-editor text-editor-init"
  data-mode="popover"
  data-placeholder="Description"
>
  ...
</div>

在 camelCase 中使用的参数,例如 imageUrlText,在 data- 属性中应采用 kebab-case 形式,如 data-image-url-text

CSS 变量

以下是与之相关的 CSS 变量(CSS 自定义属性)列表。

:root {
  --f7-text-editor-font-size: inherit;
  --f7-text-editor-font-weight: inherit;
  --f7-text-editor-border-width: 1px;
  --f7-text-editor-height: 250px;
  --f7-text-editor-margin: 16px;
  --f7-text-editor-padding: 8px;
  --f7-text-editor-button-bg-color: transparent;
  --f7-text-editor-button-size: 28px;
  --f7-text-editor-button-icon-size: 20px;
  --f7-text-editor-button-margin: 2px;
  --f7-text-editor-text-color: #000;
  --f7-text-editor-bg-color: #fff;
  --f7-text-editor-button-divider-color: rgba(0, 0, 0, 0.15);
}
:root .dark,
:root.dark {
  --f7-text-editor-bg-color: #121212;
  --f7-text-editor-text-color: #fff;
  --f7-text-editor-button-divider-color: rgba(255, 255, 255, 0.15);
}
.ios {
  --f7-text-editor-toolbar-padding: 6px;
  --f7-text-editor-button-border-radius: 2px;
  --f7-text-editor-placeholder-color: rgba(0, 0, 0, 0.35);
  --f7-text-editor-toolbar-border-color: rgba(0, 0, 0, 0.25);
  --f7-text-editor-toolbar-bg-color: #fff;
  --f7-text-editor-border-color: rgba(0, 0, 0, 0.1);
  --f7-text-editor-button-text-color: #333;
}
.ios .dark,
.ios.dark {
  --f7-text-editor-placeholder-color: rgba(255, 255, 255, 0.35);
  --f7-text-editor-toolbar-bg-color: #121212;
  --f7-text-editor-toolbar-border-color: rgba(255, 255, 255, 0.1);
  --f7-text-editor-toolbar-bg-color: #202020;
  --f7-text-editor-border-color: rgba(255, 255, 255, 0.1);
  --f7-text-editor-button-text-color: #fff;
}
.md {
  --f7-text-editor-button-border-radius: 8px;
  --f7-text-editor-toolbar-padding: 8px;
}
.md,
.md .dark,
.md [class*='color-'] {
  --f7-text-editor-placeholder-color: var(--f7-md-on-surface-variant);
  --f7-text-editor-toolbar-bg-color: var(--f7-md-surface-1);
  --f7-text-editor-border-color: var(--f7-md-outline);
  --f7-text-editor-button-text-color: var(--f7-md-on-surface);
}

示例

text-editor.html
<template>
  <div class="page">
    <div class="navbar">
      <div class="navbar-bg"></div>
      <div class="navbar-inner sliding">
        <div class="title">Text Editor</div>
      </div>
    </div>
    <div class="page-content">
      <div class="block">
        <p>Framework7 comes with a touch-friendly Rich Text Editor component. It is based on modern "contenteditable"
          API so it should work everywhere as is.</p>
        <p>It comes with the basic set of formatting features. But its functionality can be easily extended and
          customized to fit any requirements.</p>
      </div>

      <div class="block-title">Default Setup</div>
      <div class="text-editor text-editor-init">
        <div class="text-editor-content" contenteditable></div>
      </div>

      <div class="block-title">With Placeholder</div>
      <div class="text-editor text-editor-init" data-placeholder="Enter text...">
        <div class="text-editor-content" contenteditable></div>
      </div>

      <div class="block-title">With Default Value</div>
      <div class="text-editor text-editor-init" data-placeholder="Enter text...">
        <div class="text-editor-content" contenteditable>
          <p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Consequatur sunt, sapiente quis eligendi
            consectetur hic asperiores assumenda quidem dolore quasi iusto tenetur commodi qui ullam sint sed alias!
            Consequatur, dolor!</p>
          <p>Provident reiciendis exercitationem reprehenderit amet repellat laborum, sequi id quam quis quo quos facere
            veniam ad libero dolorum animi. Nobis, illum culpa explicabo dolorem vitae ut dolor at reprehenderit magnam?
          </p>
          <p>Qui, animi. Dolores dicta, nobis aut expedita enim eum assumenda modi, blanditiis voluptatibus excepturi
            non pariatur. Facilis fugit facere sequi molestias nemo in, suscipit inventore consequuntur, repellat
            perferendis, voluptas odit.</p>
          <p>Tempora voluptates, doloribus architecto eligendi numquam facilis perspiciatis autem quam voluptas maxime
            ratione harum laudantium cum deleniti. In, alias deserunt voluptatibus eligendi libero nobis est unde et
            perspiciatis cumque voluptatum.</p>
          <p>Quam error doloribus qui laboriosam eligendi. Aspernatur quam pariatur perspiciatis reprehenderit atque
            dicta culpa, aut rem? Assumenda, quibusdam? Reprehenderit necessitatibus facere nemo iure maiores porro
            voluptates accusamus quibusdam. Nesciunt, assumenda?</p>
        </div>
      </div>

      <div class="block-title">Specific Buttons</div>
      <div class="block-header">It is possible to customize which buttons (commands) to show.</div>
      <div class="text-editor text-editor-init" data-placeholder="Enter text..."
        data-buttons='[["bold", "italic", "underline", "strikeThrough"], ["orderedList", "unorderedList"]]'>
        <div class="text-editor-content" contenteditable></div>
      </div>

      <div class="block-title">Custom Button</div>
      <div class="block-header">It is possible to create custom editor buttons. Here is the custom "hr" button that adds
        horizontal rule:</div>
      <div class="text-editor text-editor-custom-buttons">
        <div class="text-editor-content" contenteditable></div>
      </div>

      <div class="block-title">Resizable</div>
      <div class="block-header">Editor will be resized based on its content.</div>
      <div class="text-editor text-editor-init text-editor-resizable" data-placeholder="Enter text..."
        data-buttons='["bold", "italic", "underline", "strikeThrough"]'>
        <div class="text-editor-content" contenteditable></div>
      </div>

      <div class="block-title">Popover Mode</div>
      <div class="block-header">In this mode, there is no toolbar with buttons, but they appear as popover when you
        select any text in editor.</div>
      <div class="text-editor text-editor-init" data-placeholder="Enter text..."
        data-buttons='["bold", "italic", "underline", "strikeThrough"]' data-mode="popover"
        style="--f7-text-editor-height: 150px">
        <div class="text-editor-content" contenteditable></div>
      </div>

      <div class="block-title">Keyboard Toolbar Mode</div>
      <div class="block-header">In this mode, toolbar with buttons will appear on top of virtual keyboard when editor is
        in the focus. It is supported only in iOS, Android cordova apps and in Android Chrome. When not supported it
        will fallback to "popover" mode.</div>
      <div class="text-editor text-editor-init" data-placeholder="Enter text..." data-mode="keyboard-toolbar"
        style="--f7-text-editor-height: 150px">
        <div class="text-editor-content" contenteditable></div>
      </div>

      <div class="block-title">As List Input</div>
      <div class="block-header">Text editor can be used in list with other inputs. In this example it is enabled with
        "keyboard-toolbar"/"popover" type for "About" field.</div>
      <div class="list list-strong-ios list-dividers-ios list-outline-ios">
        <ul>
          <li class="item-content item-input">
            <div class="item-media">
              <i class="icon demo-list-icon"></i>
            </div>
            <div class="item-inner">
              <div class="item-title item-label">Name</div>
              <div class="item-input-wrap">
                <input type="text" placeholder="Your name" />
              </div>
            </div>
          </li>
          <li class="item-content item-input">
            <div class="item-media">
              <i class="icon demo-list-icon"></i>
            </div>
            <div class="item-inner">
              <div class="item-title item-label">About</div>
              <div class="item-input-wrap">
                <div class="text-editor text-editor-init text-editor-resizable" data-placeholder="About"
                  data-buttons='["bold", "italic", "underline", "strikeThrough"]' data-mode="popover">
                  <div class="text-editor-content" contenteditable></div>
                </div>
              </div>
            </div>
          </li>
        </ul>
      </div>
    </div>
  </div>
</template>
<script>
  export default (props, { $f7, $el, $on }) => {
    let textEditorCustomButtons;
    $on('pageInit', () => {
      textEditorCustomButtons = $f7.textEditor.create({
        el: $el.value.find('.text-editor-custom-buttons'),
        // define custom "hr" button
        customButtons: {
          hr: {
            content: '<hr>',
            onClick(editor, buttonEl) {
              document.execCommand('insertHorizontalRule', false);
            },
          },
        },
        buttons: [["bold", "italic", "underline", "strikeThrough"], "hr"],
      });
    });
    $on('pageBeforeRemove', () => {
      textEditorCustomButtons.destroy()
    });

    return $render;
  };
</script>