javascript – 如何从CKEditor 5中的Insert事件中获取文本?

我正在尝试从CKEditor 5处理插入事件.

editor.document.on("change",(eventInfo,type,data) => {
  switch (type) {
    case "insert":
    console.log(type,data);
    break;
  }
});

在编辑器中键入时,将调用回调.事件回调中的data参数看起来像这样:

{
  range: {
    start: {
      root: { ... },path: [0,14]
    },end: {
      root: { ... },15]
    }
  }
}

我没有看到一种方便的方法来确定实际插入的文本.我可以调用data.range.root.getNodeByPath(data.range.start.path);这似乎让我得到了插入文本的文本节点.那么我们应该查看文本节点的数据字段吗?我们是否应该假设路径中的最后一项始终是范围开始和结束的偏移量并使用它来进行子串?我认为插入事件也是为插入非文本类型的东西(例如元素)而触发的.我们怎么知道这确实是事件的文本类型?

有没有我想念的东西,或者只有不同的方式一起完成这一切?

最佳答案
首先,让我描述你目前是如何做到的(2018年1月).请记住,CKEditor 5现在正在进行大规模的重构,事情会发生变化.最后,我将描述完成此重构后的样子.如果你不介意等待一段时间让重构结束,你可以跳到后面的部分.

编辑:1.0.0-beta.1于3月15日发布,因此您可以跳转到“自2018年3月以来”部分.

直到2018年3月(高达1.0.0-alpha.2)

(如果您需要了解有关某些类API或事件的更多信息,请参见please check out the docs.)

您最好的选择就是迭代插入的范围.

let data = '';

for ( const child of data.range.getItems() ) {
    if ( child.is( 'textProxy' ) ) {
        data += child.data;
    }
}

请注意,迭代整个范围时始终返回TextProxy实例,即使整个Text节点包含在范围内也是如此.

(您可以在CKEditor5 & Angular2 – Getting exact position of caret on click inside editor to grab data中阅读有关字符串化字符串的更多信息.)

请记住,InsertOperation可能会插入多个不同类型的节点.大多数情况下,这些只是单个字符或元素,但可以提供更多节点.这就是为什么数据中没有额外的data.item或类似属性的原因.可能有data.items,但那些与Array.from(data.range.getItems())相同.

对文档#进行更改

您之后没有提到要对此信息做什么.获取范围的内容很简单,但如果您想以某种方式对这些更改做出反应并更改模型,那么您需要小心.触发change事件时,可能已经有更多的更改入队.例如:

>可以从协作服务中同时获得更多更改,
>一个不同的特征可能已经对同一个变化做出了反应,并将其变化排列,这可能会使模型不同.

如果你确切知道你将使用哪些功能,你可能会坚持我的建议.请记住,您对模型所做的任何更改都应在Document#enqueueChanges()块中完成(否则,它将不会呈现).

如果您希望此解决方案具有防弹性,您可能必须这样做:

>在迭代data.range子节点时,如果找到TextProxy,则创建跨越该节点的LiveRange.
>然后,在enqueueChanges()块中,遍历存储的LiveRanges并通过其子项.
>为每个找到的TextProxy实例执行逻辑.
>记得事后销毁()所有的LiveRanges.

正如您所看到的,这似乎不必要地复杂化.提供一个开放灵活的框架(如CKE5)存在一些缺点,并且考虑到所有边缘情况都是其中之一.但确实如此,它可能更简单,这就是我们首先开始重构的原因.

自2018年3月起(从1.0.0-beta.1开始)

1.0.0-beta.1中的重大变化将是模型的引入.Differ类,改进的事件结构和模型的大部分新API.

首先,Document#event:在所有enqueueChange块完成后将触发更改.这意味着您不必担心其他更改是否会影响您在回调中所做出的更改.

此外,将添加engine.Document#registerPostFixer()方法,您将能够使用它来注册回调.更改事件仍然可用,但更改事件和registerPostFixer之间会略有不同(我们将在指南和文档中介绍它们).

其次,您将可以访问model.Differ实例,该实例将在第一次更改之前的模型状态与您希望对更改作出反应的时刻的模型状态之间存储差异.您将迭代所有差异项并检查确切的位置和更改的位置.

除此之外,还将在重构中进行许多其他更改,下面的代码片段也会反映出来.所以,在新的世界里,它看起来像这样:

editor.document.registerPostFixer( writer => {
    const changes = editor.document.differ.getChanges();

    for ( const entry of changes ) {
        if ( entry.type == 'insert' && entry.name == '$text' ) {
            // Use `writer` to do your logic here.
            // `entry` also contains `length` and `position` properties.
        }
    }
} );

代码方面,它可能比第一个代码段更多,但是:

>第一个片段不完整.
>在新方法中要考虑的边缘情况要少得多.
>新方法更容易掌握 – 在完成所有更改后,您可以使用所有更改,而不是在其他更改排队时对更改作出反应,并且可能会使模型陷入困境.

编写器是一个对象,将用于对模型进行更改(而不是Document#batch API).它将包含insertText(),insertElement(),remove()等方法.

您可以检查model.Differ API和测试,因为它们已在master branch上可用.(内部代码将更改,但API将保持不变.)

相关文章

前言 做过web项目开发的人对layer弹层组件肯定不陌生,作为l...
前言 前端表单校验是过滤无效数据、假数据、有毒数据的第一步...
前言 图片上传是web项目常见的需求,我基于之前的博客的代码...
前言 导出Excel文件这个功能,通常都是在后端实现返回前端一...
前言 众所周知,js是单线程的,从上往下,从左往右依次执行,...
前言 项目开发中,我们可能会碰到这样的需求:select标签,禁...