簡易富文本編輯器

背景

運營同事在微信公衆號發佈文章時,經常按照如下步驟操做:html

  • 打開「秀米」網 =》 挑選模版 =》 編輯好內容 =》 一鍵複製代碼vue

  • 打開微信公衆平臺 =》 新建文章 =》 粘貼到編輯器裏 =》 確認發佈react

緊接着,這個工做多了一塊內容 —— 把內容同步到某個產品的觸屏網站中。jquery

因爲當下尚未資源開發一款相似「秀米」的產品,最終決定在以前的基礎上增長以下步驟:git

  • 打開觸屏網站的內容管理平臺 =》 新建文章 =》 粘貼到編輯器裏 =》 確認發佈github

問題

本來覺得只是像在微信公衆平臺同樣,在富文本編輯器裏粘貼便可,過程當中卻發現粘貼後部分樣式和標籤丟失微信

分析

Quill v1.3.0

內容管理平臺中基於 Vue.js 開發,富文本編輯器使用的是 Quill。微信公衆平臺

而 Quill 簡潔易用的優勢,現在成了它的缺點 —— 它只保留特定的標籤和樣式,且沒有可供修改的配置。less

因而,決定選型其它富文本編輯器。編輯器

Simditor

默認配置下和 Quill 問題同樣,而 Simditor 能夠經過配置來添加所需標籤和樣式。但有以下問題:

  • 標籤須要手動一個個加進去,而樣式則須要針對每一個標籤分別添加。這種方案過程太費勁、容易遺漏

  • github 上大約是 2-3 年前的更新

  • 依賴 jquery 實現

wangeditor3

記得它早期版本依賴 jquery,在 github 上粗看了最新的代碼,3天前還在更新,已經無依賴,但兼容性要求 ie10 +。
注意到一個驚喜之處,他配套了 vue 和 react 相關的組件。
惋惜的是,它的問題和 Quill 同樣 —— 無法配置。

其它

一些早期版本的富文本編輯器,基本上沒有對標籤和樣式的限制,但缺乏工程化支持

解決方案

考慮到,無非是粘貼這麼一個簡單的需求,並且由於是內部系統,兼容性不是太大問題。
那麼,何苦費勁用功能那麼複雜的編輯器呢。

clipboardData

能夠經過事件對象來訪問黏貼板

event.clipboardData.getData('text/html')

MDN 上對 getData(format) 的惟一必填參數 format 的解釋,有點難理解

A DOMString representing the type of data to retrieve.

經過網上的一些例子,取值範圍大概能夠認爲等價於 MIME ,還包括 'Text'null

一個神奇的屬性 contenteditable

其實,解決了黏貼的問題,已經能夠告一段落了。
恰巧這時候查到了 contenteditable 相關資料,發現就是一個活脫脫的原生富文本編輯器。

Vue 組件

<template>
    <div class="ui-editor"
         contenteditable="true"
         @paste="paste"
         @input="input"></div>
</template>
<script>
    export default {
        props: {
            value: String
        },
        data() {
            return {
                html: ''
            }
        },
        methods: {
            paste(e) {
                e.preventDefault()
                const html = e.clipboardData.getData('text/html')
                document.execCommand('insertHTML', false, html)
                this.input()
            },
            input() {
                const v = this.$el.innerHTML
                this.html = v
                this.$emit('input', v)
            }
        },
        watch: {
            value(v) {
                if (v !== this.html) {
                    this.$el.innerHTML = v
                }
            }
        },
        mounted() {
            const v = this.value
            if (v) {
                this.$el.innerHTML = v
                this.html = v
            }
        }
    }
</script>
<style lang="less">
    .ui-editor {
        margin: 10px auto;
        width: 374px;
        min-height: 300px;
        padding: 0 15px;
        box-shadow: inset 0 0 12px rgba(63, 70, 82, 0.5);
        background-color: #fff;
        overflow: hidden;
        user-select: all;

        &:hover {
            outline: 1px solid red;
        }
    }
</style>

例子

<template>
    <uEditor v-model="content" />
</template>
<script>
    import uEditor from './editor.vue'
    
    export default {
        components: {
            uEditor
        },
        data() {
            return {
                content:''
            }
        }
    }
</script>
相關文章
相關標籤/搜索