文字編輯器

Framework7 附帶一個觸控友善的富文字編輯器元件。它基於現代的「可編輯內容」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編輯器 placeholder 內容,在編輯器為空時顯示。預設未指定
modestringtoolbar

文字編輯器按鈕模式。可以是

  • toolbar - 它會在文字編輯器容器元素中新增帶有編輯器按鈕的工具列
  • popover - 它會在編輯器中所選文字的上方顯示帶有編輯器按鈕的 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'],
]
分隔線布林值true在按鈕群組之間加入視覺分隔線
imageUrlTextstring插入圖片網址在圖片網址要求上顯示的提示文字
linkUrlTextstring插入連結網址在連結網址要求上顯示的提示文字
clearFormattingOnPaste布林值true啟用後,它會清除從剪貼簿貼上的任何格式
customButtons物件

包含自訂按鈕的物件。物件屬性金鑰是應在 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']
})
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 元素
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 事件,以及在 app 和文字編輯器實例上觸發事件

DOM 事件

事件說明
texteditor:init編輯器初始化時會觸發事件
texteditor:change編輯器值變更時會觸發事件
texteditor:input編輯器內容「輸入」事件時會觸發事件
texteditor:focus編輯器內容獲得焦點時會觸發事件
texteditor:blur編輯器內容失去焦點時會觸發事件
texteditor:buttonclick編輯器按鈕被點擊時會觸發事件
texteditor:keyboardopen編輯器鍵盤工具列出現時會觸發事件
texteditor:keyboardclose編輯器鍵盤工具列消失時會觸發事件
texteditor:popoveropen編輯器彈出視窗開啟時會觸發事件
texteditor:popoverclose編輯器彈出視窗關閉時會觸發事件
texteditor:beforedestroy文字編輯器實例即將被銷毀之前會觸發事件

App 和文字編輯器實例事件

文字編輯器實例會在自身實例和 app 實例上發出事件。App 實例事件名稱相同,但前面加上 textEditor

事件目標參數說明
inittextEditor(editor)編輯器初始化時會觸發事件。
textEditorInitapp
changetextEditor(editor)編輯器初始化時會觸發事件。
textEditorChangeapp
inputtextEditor(editor)編輯器內容「輸入」事件時會觸發事件。
textEditorInputapp
focustextEditor(editor)編輯器內容獲得焦點時會觸發事件。
textEditorFocusapp
模糊textEditor(editor)事件會在編輯器的內容模糊時觸發。
textEditorBlurapp
buttonClicktextEditor(編輯器,按鈕)事件會在編輯器按鈕點擊時觸發。
作為第二個參數,事件處理器會收到點擊按鈕的 ID,例如 bold
textEditorButtonClickapp
keyboardOpentextEditor(editor)當編輯器鍵盤工具列出現時,事件會觸發。
textEditorKeyboardOpenapp
keyboardClosetextEditor(editor)當編輯器鍵盤工具列消失時,事件會觸發。
textEditorKeyboardCloseapp
popoverOpentextEditor(editor)事件會在編輯器彈出視窗開啟時觸發。
textEditorPopoverOpenapp
popoverClosetextEditor(editor)事件會在編輯器彈出視窗關閉時觸發。
textEditorPopoverCloseapp
beforeDestroytextEditor(editor)事件會在 Text Editor 執行個體被銷毀之前觸發。
textEditorBeforeDestroyapp

Text Editor 自動初始化

如果您不需要使用 Text Editor API,而且您的 Text Editor 在頁面內部,並在頁面初始化時出現在 DOM 中,那麼它可以透過新增額外的 text-editor-init 類別來自動初始化

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

在這種情況下,如果您需要存取已建立的 Text Editor 執行個體,您可以使用 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>