流星中的文字复制?

时间:2015-03-27 01:56:49

标签: javascript meteor spacebars

我试图制作一个Meteor应用程序,允许多人同时编辑一组文本(想想Google Docs / Drive)。

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

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

<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. 如何阻止它发生?
  3. 如果您希望亲自看到问题而无需运行流星服务器(虽然我已经为您提供了所有代码的所有代码......)我把它扔了here

3 个答案:

答案 0 :(得分:1)

这是一个已知问题,详细讨论here。我正在使用this solution(来自Swavek)并且效果很好。

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

  1. 流星,虽然反应性
  2. 负责管理contenteditable div内部的浏览器代码。
  3. 解决方法是告诉Meteor不要操纵contenteditable div的内部,而是刷新整个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>';
      }
    });
    

答案 1 :(得分:0)

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

我只是在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());
    }
  });
}

答案 2 :(得分:0)

这既感觉又看起来像黑客......但它比原始代码略好,所以我会分享它作为答案:

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

示例:

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

注意事项:

  1. 每次击键后文字都会瞬间消失(有时它会如此简短,你甚至都没有注意到它。)
  2. 每次键入时光标都会跳回文本的开头。 (但光标也有在原始代码中跳跃的倾向。)
  3. 这两个警告都非常可怕......基本上所有发生的事情都是我交换了重复的文字,文字暂时消失了。

    一个真正的解决方案是,如果有某种我喜欢的方式,挂钩到空格键或其他东西......就像,我需要有一些代码在空格键反应性更新后运行。或者,如果我可以修改空格键如何反应更新。也许我会查看Spacebars上的文档和/或来源,并根据我发现的内容提交错误报告或功能请求...