解决将纯文本粘贴进 CKEditor 5 编辑器时换行符没有转换成段落的问题


CKEditor 5 编辑器在粘贴纯文本时,并没有将换行符转换成段落,而是转换成一个 <br/> 标签,导致整篇文章成为一个段落。这样,在修改段落格式时会带来一些问题。比如你想修改其中一个段落的对齐方式,修改之后,你会发现整篇文章的对齐方式都变了。
关于这个问题,官方文档中找到了一个相关说明,具体请参见 Pasting plain text

Pasting plain text with a double line break will turn the break into a paragraph. A single line break will instead be turned into a soft break upon pasting.

翻译过来就是,在粘贴纯文本时,两个换行符才会转换成段落,一个换行符只会转换成一个软换行。软换行在html里就是一个<br/>标签。

这种处理方式不太符合人们的使用习惯,要想修改这种处理方式,将每个换行符都转换成段落,只能自己编写插件,官方没有提供相关的配置选项。

下面是我写的插件,有需要的同学可以拿去用。

import {Plugin} from '@ckeditor/ckeditor5-core';
import ClipboardPipeline from '@ckeditor/ckeditor5-clipboard/src/clipboardpipeline'
import ClipboardObserver from '@ckeditor/ckeditor5-clipboard/src/clipboardobserver'

function plainTextToHtml(text) {
    text = text
        // Encode <>.
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        // Creates a paragraph for each single line break.
        .replace(/\r?\n/g, '</p><p>')
        // Preserve trailing spaces (only the first and last one – the rest is handled below).
        .replace(/^\s/, '&nbsp;')
        .replace(/\s$/, '&nbsp;')
        // Preserve other subsequent spaces now.
        .replace(/\s\s/g, ' &nbsp;');

    if (text.includes('</p><p>')) {
        // If we created paragraphs above, add the trailing ones.
        text = `<p>${text}</p>`;
    }

    // TODO:
    // * What about '\nfoo' vs ' foo'?

    return text;
}

/**
 * CKEditor在粘贴纯文本时,默认将1个换行符转换成<br/>标签,两个换行符才转换成段落,不太符合我们的使用习惯。
 * 本插件将把所有换行符均转换成段落。
 */
export default class PastPlainTextFormatting extends Plugin {
    static get requires() {
        return [ClipboardPipeline];
    }

    static get pluginName() {
        return 'PastPlainTextFormatting';
    }

    init() {
        const editor = this.editor;
        const view = editor.editing.view;
        const viewDocument = view.document;

        view.addObserver(ClipboardObserver);

        this.listenTo(viewDocument, 'clipboardInput', (evt, data) => {
            const dataTransfer = data.dataTransfer;
            let content = data.content || '';

            if (!content && dataTransfer.getData('text/plain')) {
                content = plainTextToHtml(dataTransfer.getData('text/plain'));
                data.content = this.editor.data.htmlProcessor.toView(content);
            }
        })
    }
}

发表回复

您的电子邮箱地址不会被公开。

正在检测……