2

背景

运营同事在微信公众号发布文章时,常常按照以下步骤操作:

  • 打开“秀米”网 =》 挑选模版 =》 编辑好内容 =》 一键复制代码

  • 打开微信公众平台 =》 新建文章 =》 粘贴到编辑器里 =》 确认发布

紧接着,这个工作多了一块内容 —— 把内容同步到某个产品的触屏网站中。

由于当下还没有资源开发一款类似“秀米”的产品,最终决定在之前的基础上增加如下步骤:

  • 打开触屏网站的内容管理平台 =》 新建文章 =》 粘贴到编辑器里 =》 确认发布

问题

原本以为只是像在微信公众平台一样,在富文本编辑器里粘贴即可,过程中却发现粘贴后部分样式和标签丢失

分析

Quill v1.3.0

内容管理平台中基于 Vue.js 开发,富文本编辑器使用的是 Quill。

而 Quill 简洁易用的优点,如今成了它的缺点 —— 它只保留特定的标签和样式,且没有可供修改的配置。

于是,决定选型其它富文本编辑器。

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>

siwuxie
528 声望67 粉丝

404