文本编辑器

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 方法

让我们看看与文本编辑器相关的 App 方法:

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

  • 参数 - 对象. 带有文本编辑器参数的对象

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

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

  • el - HTMLElement字符串(使用 CSS 选择器) 或对象. 要销毁的文本编辑器元素或文本编辑器实例。

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

  • el - HTMLElement字符串(带 CSS 选择器)。文本编辑器元素。

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

例如:

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

文本编辑器参数

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

参数类型默认描述
elHTMLElement
字符串
文本编辑器元素。HTMLElement 或编辑器元素的 CSS 选择器字符串
字符串

文本编辑器初始 HTML 内容值。初始值也可以放置为text-editor-content元素的 inner HTML 内容,例如:

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

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

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

带有编辑器按钮的数组,或带有编辑器按钮数组的数组(组)。默认情况下所有按钮都启用,其默认值是:

[
  ['bold', 'italic', 'underline', 'strikeThrough'],
  ['orderedList', 'unorderedList'],
  ['link', 'image'],
  ['paragraph', 'h1', 'h2', 'h3'],
  ['alignLeft', 'alignCenter', 'alignRight', 'alignJustify'],
  ['subscript', 'superscript'],
  ['indent', 'outdent'],
]
dividers布尔值true在按钮组之间添加视觉分隔符
imageUrlText字符串插入图像 URL图像 URL 请求时出现的提示文本
linkUrlText字符串插入链接 URL链接 URL 请求时出现的提示文本
clearFormattingOnPaste布尔值true当启用时,它将清除从剪贴板粘贴的任何格式
customButtons对象

带有自定义按钮的对象。对象属性键是用于启用它的按钮 ID。buttons例如,要指定将添加

For example to specify custom button that will add <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']
})
on对象

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

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 元素的 Dom7 实例
textEditor.$contentEl包含文本编辑器内容 (contenteditalbe) HTML 元素的 Dom7 实例
textEditor.value文本编辑器的 HTML 值
textEditor.params包含初始化参数的对象
方法
textEditor.setValue()设置新的文本编辑器值。value是 HTML 字符串。
textEditor.getValue()返回当前文本编辑器值
textEditor.clearValue()清除文本编辑器值
textEditor.getSelectionRange()返回当前选择范围
textEditor.setSelectionRange(范围)根据传递的范围设置选择
textEditor.destroy()销毁文本编辑器实例并移除所有事件
textEditor.on(事件上触发, 处理程序)添加事件处理程序
textEditor.once(事件上触发, 处理程序)添加在触发后将被移除的事件处理程序
textEditor.off(事件上触发, 处理程序)移除事件处理程序
textEditor.off(事件上触发)移除指定事件的所有处理程序
textEditor.emit(事件上触发, ...args)在实例上触发事件

文本编辑器事件

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

DOM 事件

事件描述
texteditor:init当编辑器初始化时将触发此事件
文本编辑器:更改当编辑器值发生变化时将触发事件
texteditor:input当编辑器内容发生“input”事件时将触发事件
texteditor:focus当编辑器内容获得焦点时将触发事件
texteditor:blur当编辑器内容失去焦点时将触发事件
texteditor:buttonclick当编辑器按钮被点击时将触发事件
texteditor:keyboardopen当编辑器键盘工具栏出现时将触发事件
texteditor:keyboardclose当编辑器键盘工具栏消失时将触发事件
texteditor:popoveropen当编辑器弹出框打开时将触发事件
texteditor:popoverclose当编辑器弹出框关闭时将触发事件
texteditor:beforedestroy在文本编辑器实例被销毁之前将触发事件

App 和文本编辑器实例事件

文本编辑器实例在自身实例和 App 实例上发出事件。App 实例事件具有相同名称,并以textEditor.

事件Target参数描述
inittextEditor(editor)当编辑器初始化时将触发此事件。
textEditorInitapp
changetextEditor(editor)当编辑器初始化时将触发此事件。
textEditorChangeapp
inputtextEditor(editor)当编辑器内容触发 "input" 事件时将触发此事件。
textEditorInputapp
focustextEditor(editor)当编辑器内容获得焦点时将触发此事件。
textEditorFocusapp
blurtextEditor(editor)当编辑器内容失去焦点时将触发此事件。
textEditorBlurapp
buttonClicktextEditor(editor, button)当编辑器按钮被点击时将触发此事件。
作为第二个参数,事件处理程序接收被点击按钮的 ID,例如bold
textEditorButtonClickapp
keyboardOpentextEditor(editor)当编辑器键盘工具栏出现时将触发此事件。
textEditorKeyboardOpenapp
keyboardClosetextEditor(editor)当编辑器键盘工具栏消失时将触发此事件。
textEditorKeyboardCloseapp
popoverOpentextEditor(editor)当编辑器弹出窗口打开时将触发此事件。
textEditorPopoverOpenapp
popoverClosetextEditor(editor)当编辑器弹出窗口关闭时将触发此事件。
textEditorPopoverCloseapp
beforeDestroytextEditor(editor)在文本编辑器实例将被销毁之前将触发此事件。
textEditorBeforeDestroyapp

文本编辑器自动初始化

如果你不需要使用文本编辑器 API,并且你的文本编辑器在页面内,并且在页面初始化时以 DOM 形式呈现,那么它可以通过仅添加额外的text-editor-init class:

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

自动初始化。在这种情况下,如果你需要访问创建的文本编辑器实例,你可以使用app.textEditor.get app method:

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>