Meteor中的文本复制

Text Duplicating in Meteor?

本文关键字:复制 文本 Meteor      更新时间:2023-09-26

我正在尝试制作一款Meteor应用程序,它允许多人同时编辑一段文本(想想谷歌文档/Drive)。

我想,为了做到这一点,我需要一个模板,它只显示当前数据库中的文本,然后每当修改文本时,它都需要更新数据库中的文字。

我能够在下面的这个最小复制中从我的完整应用程序中复制相同的问题(设计为由单个用户使用,而不是由多个用户使用,因此从使用Mongo Collection切换为会话。)

<body>
  {{> hello}}
</body>
<template name="hello">
  <pre contentEditable="true">{{text}}</pre>
</template>

(如果我使用div而不是pre,也会出现完全相同的问题。)

if (Meteor.isClient) {
  Session.setDefault('text', "Edit me!");
  Template.hello.helpers({
    text: function () {
      return Session.get('text');
    }
  });
  Template.hello.events({
    "input pre": function (event) {
      Session.set('text', $(event.target).text());
    }
  });
}

尝试在应用程序中键入一点,错误应该很快就会显现出来:每次击键都会获取所有现有文本,并将其附加到您键入的内容中(因此,每次击键时,它都会复制所有文本)。这是非常奇怪的部分:这种行为并不总是立即开始。。。事实上,我还没有找到任何特别可靠的方法来复制它。一旦它复制了一次文本,它就会可靠地在每次击键时一次又一次地复制,直到你刷新页面。刷新页面后,有时错误会在下一次按键时再次出现,其他时候可能需要大约20次按键才能出现。

我已经在Safari 8(包括OS X和iOS)、Chrome(包括OS X和Windows)和Firefox(仅包括OS X)上测试过这个问题,每个浏览器都会出现这个问题。

如果你还不能复制它,试着突出显示所有文本,删除它,然后键入。也试着开始一条新的线路。我发现这些行为似乎更有可能引发文本重复,但即使是这些行为也不会一直引发问题。

我的问题是:

  1. 为什么会出现此错误
  2. 我如何才能阻止它的发生

如果你想在不运行流星服务器的情况下直接看到这个问题(尽管我已经给了你所有的代码…),我把它扔到了这里。

这是一个已知的问题,在这里详细讨论。我使用这个解决方案(来自Swavek),效果很好。

简单地说,当两个人同时操作相同的DOM元素时,问题就出现了:

  1. Meteor,尽管反应性
  2. 负责管理contenteditablediv内部的浏览器代码

解决方案是告诉Meteor不要操作contenteditablediv的内部,而是刷新整个div。你这样做:

<body>
  {{> hello}}
</body>
<template name="hello">
  {{{getContenteditableDiv}}}  <!-- Beware: triple brackets! -->
</template>
Template.hello.helpers({
  getContenteditableDiv: function() {
    return '<pre contentEditable="true">' + Session.get('text') + '</pre>';
  }
});

这感觉和看起来都像黑客。。。但它比原始代码稍微好一点,所以我将把它作为答案分享:

在每次input之后,在将新内容插入后备存储之后,使用$(event.target).contents().remove();清除该字段。

示例:

Template.hello.events({
  "input pre": function (event) {
    Session.set('text', $(event.target).text());
    $(event.target).contents().remove();
  }
});

注意事项:

  1. 每次按键后,文本都会瞬间消失(有时它太简短了,你甚至都没有注意到。)
  2. 每次键入时,光标都会跳回到文本的开头。(但光标在原始代码中也有跳跃的趋势。)

这两个警告都非常可怕。。。基本上,所有发生的事情都是我把出现的重复文本换成了暂时消失的文本。

一个真正的解决方案是,如果有某种我喜欢的方式,挂上空格键或其他什么。。。比如,我需要一些在空格键反应性更新后立即运行的代码。或者我是否可以修改空格键的反应更新方式。也许我会查看Spacebar上的文档和/或源代码,并根据我的发现提交错误报告或功能请求。。。

我认为这是因为您捕获了所有事件,而不是将其缩小到特定的事件类型。

我只是在MeteorPad上试了几分钟,它从未复制过文本:

/main.html

<body>
  {{> hello}}
</body>
<template name="hello">
  <pre contentEditable="true">{{text}}</pre>
</template>

/client/app.js

if (Meteor.isClient) {
  Session.setDefault('text', "Edit me!");
  Template.hello.helpers({
    text: function () {
      return Session.get('text');
    }
  });
  Template.hello.events({
    "keyup pre": function (event) {
      $(event.target).text("I was called");
      Session.set('text', $(event.target).text());
    }
  });
}