在 Meteor 中复制文本?
Text Duplicating in Meteor?
我正在尝试制作一个允许多人同时编辑文本正文的 Meteor 应用程序(想想 Google Docs/Drive)。
我想为了做到这一点,我需要一个模板,它只显示数据库中当前的文本,然后每当修改文本时,它需要更新数据库中的文本。
我能够在下面这个最小复制中重现我的完整应用程序中的相同问题(设计供单个用户而不是多个用户使用,因此从使用 Mongo 集合切换到会话。 )
<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)并且该问题出现在每个浏览器中。
如果您还不能重现它,请尝试突出显示所有文本,将其删除,然后键入。也尝试开始一个新行。我发现这些操作似乎更有可能引发文本重复,但即使是那些操作也不会始终引发问题。
我的问题是:
- 为什么会出现这个错误?
- 我怎样才能阻止它发生?
如果你想直接看到问题而不必 运行 流星服务器(虽然我已经给了你所有的代码......)我把它扔了 here.
我认为这是因为您正在捕获所有事件,而不是将其缩小到特定事件类型。
我刚刚在 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());
}
});
}
这感觉和看起来都像是 hack...但它比原始代码稍微好一点,所以我会把它作为答案分享:
在每个 input
之后,将新内容插入后备存储后,使用 $(event.target).contents().remove();
清除字段。
示例:
Template.hello.events({
"input pre": function (event) {
Session.set('text', $(event.target).text());
$(event.target).contents().remove();
}
});
注意事项:
- 每次击键后文本都会暂时消失(有时它是如此简短,您甚至都不会注意到它。)
- 每次键入时,光标都会跳回到文本的开头。 (但光标在原始代码中也有跳跃的趋势。)
这两个警告都非常糟糕...基本上所有发生的事情都是我交换了出现的重复文本,让文本暂时消失。
一个真正的解决方案是,如果有某种我喜欢的方式,挂接到空格键或类似的东西......比如,我需要一些代码在空格键响应更新后立即运行。或者,如果我可以修改空格键的反应更新方式。也许我会查看 Spacebars 上的文档 and/or 源代码,并根据我发现的内容提交错误报告或功能请求...
这是一个已知问题,详细讨论了 here. I am using this solution(来自 Swavek)并且效果很好。
简而言之,当两个人同时操作相同的 DOM 个元素时,问题就出现了:
- 流星,虽然有反应
- 负责管理contenteditable里面的浏览器代码div。
解决方案是告诉 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>';
}
});
我正在尝试制作一个允许多人同时编辑文本正文的 Meteor 应用程序(想想 Google Docs/Drive)。
我想为了做到这一点,我需要一个模板,它只显示数据库中当前的文本,然后每当修改文本时,它需要更新数据库中的文本。
我能够在下面这个最小复制中重现我的完整应用程序中的相同问题(设计供单个用户而不是多个用户使用,因此从使用 Mongo 集合切换到会话。 )
<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)并且该问题出现在每个浏览器中。
如果您还不能重现它,请尝试突出显示所有文本,将其删除,然后键入。也尝试开始一个新行。我发现这些操作似乎更有可能引发文本重复,但即使是那些操作也不会始终引发问题。
我的问题是:
- 为什么会出现这个错误?
- 我怎样才能阻止它发生?
如果你想直接看到问题而不必 运行 流星服务器(虽然我已经给了你所有的代码......)我把它扔了 here.
我认为这是因为您正在捕获所有事件,而不是将其缩小到特定事件类型。
我刚刚在 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());
}
});
}
这感觉和看起来都像是 hack...但它比原始代码稍微好一点,所以我会把它作为答案分享:
在每个 input
之后,将新内容插入后备存储后,使用 $(event.target).contents().remove();
清除字段。
示例:
Template.hello.events({
"input pre": function (event) {
Session.set('text', $(event.target).text());
$(event.target).contents().remove();
}
});
注意事项:
- 每次击键后文本都会暂时消失(有时它是如此简短,您甚至都不会注意到它。)
- 每次键入时,光标都会跳回到文本的开头。 (但光标在原始代码中也有跳跃的趋势。)
这两个警告都非常糟糕...基本上所有发生的事情都是我交换了出现的重复文本,让文本暂时消失。
一个真正的解决方案是,如果有某种我喜欢的方式,挂接到空格键或类似的东西......比如,我需要一些代码在空格键响应更新后立即运行。或者,如果我可以修改空格键的反应更新方式。也许我会查看 Spacebars 上的文档 and/or 源代码,并根据我发现的内容提交错误报告或功能请求...
这是一个已知问题,详细讨论了 here. I am using this solution(来自 Swavek)并且效果很好。
简而言之,当两个人同时操作相同的 DOM 个元素时,问题就出现了:
- 流星,虽然有反应
- 负责管理contenteditable里面的浏览器代码div。
解决方案是告诉 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>';
}
});