我正在研究一个书写指示器,每当用户在文本区域内书写内容时,该指示器就会显示在在线列表上的名称旁边。问题是,它只对撰写者显示,而对其他选项卡/客户端不显示。
这是我的代码:
在线列表模板: imports / ui / components / chat / chat_onlinelist.html
<template name="onlineliste">
<div id="online-liste" class="onlineList">
{{#each characters}}
<div class="characterBasicInteraction" oncontextmenu="return false;">
<span class="typeIndicator" id="typeInd_{{name}}">✎</span>
<!-- TypeIndicator shows up here, code gets id with this.name
and uses it to change jquery fadeIn/fadeOut -->
<a href="/c/{{name}}" target="_blank" class="{{name}}" {{checkIfFriend}}><li>{{name}}</li></a>
<div id="panel_{{name}}" class="panelChat">
<span><b>{{name}}</b></span>
<span id="whisp">Flüstern</span>
{{{checkIfFriendButton}}}
<span>Bookmark</span>
<span>Ignore</span>
<span>Report</span>
</div>
</div>
{{/each}}
</div>
</template>
现在我到目前为止已经尝试了3种方法,所有方法都具有与上述相同的结果。
第一种方法, imports / ui / components / chat / chat.js 中的事件keydown文本区域
'keydown textarea'(event, template) {
var character = Session.get("activeChar");
var getIndicator = "#typeInd_"+character;
//setup before functions
var typingTimer; //timer identifier
var doneTypingInterval = 5000; //time in ms (5 seconds)
//on keyup, start the countdown
template.$('textarea').keyup(function(){
clearTimeout(typingTimer);
if (template.$('textarea').val()) {
typingTimer = setTimeout(doneTyping, doneTypingInterval);
}
});
//user is "finished typing,"
function doneTyping () {
template.$(getIndicator).fadeOut();
}
template.$(getIndicator).fadeIn();
template.$(".input-box_text").focusout(function() {
template.$(getIndicator).fadeOut();
})
}
方法2:在 imports / api / chat / chat.js 中编写该函数以使其在服务器上(?),并将其加载到 imports / ui / components / chat / chat.js
typeIndicator = function typeIndicator (character, getIndicator) {
var typingTimer; //timer identifier
var doneTypingInterval = 5000; //time in ms (5 seconds)
//on keyup, start the countdown
$('textarea').keyup(function(){
clearTimeout(typingTimer);
if ($('textarea').val()) {
typingTimer = setTimeout(doneTyping, doneTypingInterval);
}
});
//user is "finished typing," do something
function doneTyping () {
$(getIndicator).fadeOut();
}
//$(getIndicator).fadeIn();
$(getIndicator).fadeIn();
$(".input-box_text").focusout(function() {
$(getIndicator).fadeOut();
});
};
'keydown textarea'(event, template) {
var character = Session.get("activeChar");
var getIndicator = "#typeInd_"+character;
TypeIndicator(character, getIndicator);
}
方法3:与2基本相同,但是这次我没有使用blaze-template.events帮助器
document.addEventListener("keydown", event => {
var character = Session.get("activeChar");
var getIndicator = "#typeInd_"+character;
typeIndicator(character, getIndicator);
});
因此,这些更改似乎没有什么不同。有人可以帮忙吗?谢谢!
答案 0 :(得分:2)
从您的不同方法来看,似乎对Web应用程序和同构javascript有基本的误解。
每个客户端分别加载并运行您的应用程序的客户端版本。它们在隔离的环境(浏览器选项卡)中运行。 在该应用程序中运行代码时,它只会影响自身。 例如,您当前的方法看起来像这样:
┌─────┐
┌────▼───┐ │ ┌────────┐ ┌────────┐
│ Client │ │ │ Client │ │ Client │
└────────┘ │ └────────┘ └────────┘
└─────┘
┌────────┐
│ Server │
└────────┘
客户只是在自言自语。这就是为什么其他客户端不更新聊天指示器的原因。
(请注意,Session
也隔离到每个客户端实例)
我们想要的是让客户端告诉服务器状态已更改,然后服务器可以告诉其他客户端。然后,这些客户端可以根据更改来更新其ui:
┌────────┐ ┌────────┐ ┌────────┐
│ Client │ │ Client │ │ Client │
└────────┘ └────────┘ └────────┘
│ ▲ ▲ ▲
▼ │ │ │
┌────────┐ │ │
│ Server │───────┴───────────┘
└────────┘
为使应用程序的该单个实例与服务器或其他实例进行通信,它需要发出网络请求。 这通常是一个HTTP请求(例如XHR,fetch,jquery \ $。http),尽管在Meteor的情况下,我们在Websocket上使用了DDP。 (请注意,您可以让客户直接相互交谈,但是真正的p2p复杂得多)
在Meteor中,建议与服务器通信的方法是使用Meteor.methods
。
实时向客户端发送数据的推荐方法是将pub/sub与Mongo Collections配合使用。
当客户端订阅服务器正在发布的数据馈送时,服务器将通过网络套接字向客户端发送更新。
要针对您的聊天指示器问题执行此操作,请创建具有聊天状态的集合,设置方法并发布/订阅
import { Meteor } from "meteor/meteor";
import { Mongo } from "meteor/mongo";
// Create the collection
export const ChatStatus = new Mongo.Collection("chat-status");
// Set up the method
Meteor.methods({
updateStatus(characterId, status) {
ChatStatus.upsert({
characterId: characterId,
status: status,
});
},
});
// Publications are server-only
if (Meteor.isServer) {
Meteor.publish("chat-status", function() {
return ChatStatus.find();
});
}
// Subscriptions are client only. Normally you would put this in template code, not here.
if (Meteor.isClient) {
Meteor.subscribe("chat-status");
}
因为我们要在服务器(用于长期存储)和客户端(以便我们可以显示指示器)上访问此数据,所以将其放置在:
/both/chat-status.js
并将该文件(import '/both/chat-status.js'
)导入到
/client/main.js
和
/server/main.js
这就是同构的意思。我们将代码编写在一个地方,然后将其加载到服务器和客户端上。
现在,通过导入模板,使您的模板具有对集合的访问权限,并添加一个助手以检查状态是否为编辑
// chat.js;
import { ChatStatus } from "/both/chat-status.js";
Template.chat_onlinelist.helpers({
isEditing: function(characterId) {
const document = ChatStatus.findOne({ characterId: characterId });
if (document) {
return document.status === "editing";
} else {
return false;
}
},
});
并更新模板代码以使用新的帮助器:
{{#each characters}}
<div class="characterBasicInteraction" oncontextmenu="return false;">
{{#if isEditing _id }}
<span class="typeIndicator" id="typeInd_{{name}}">✎</span>
{{/if}}
<!-- TypeIndicator shows up here, code gets id with this.name
and uses it to change jquery fadeIn/fadeOut -->
<a href="/c/{{name}}" target="_blank" class="{{name}}" {{checkIfFriend}}><li>{{name}}</li></a>
<div id="panel_{{name}}" class="panelChat">
<span><b>{{name}}</b></span>
<span id="whisp">Flüstern</span>
{{{checkIfFriendButton}}}
<span>Bookmark</span>
<span>Ignore</span>
<span>Report</span>
</div>
</div>
{{/each}}
现在,所有客户端的模板代码都取决于数据库中的值。 最后一件事是通过调用流星方法来更新数据库中的值:
Template.chat_onlinelist.events({
"keydown textarea"(event, templateInstance) {
var character = Session.get("activeChar");
var doneTypingInterval = 5000; //time in ms (5 seconds)
// Assuming that you're storing the whole document?
Meteor.call("update-status", character._id, "editing");
// set the timer identifier on the template instance so we can get it later
templateInstance.typingTimer = setTimeout(() => {
// use empty string to denote no status
Meteor.call("update-status", character._id, "");
}, doneTypingInterval);
},
"focusout textarea"(event, templateInstance) {
if (templateInstance.typingTimer) {
clearTimeout(templateInstance.typingTimer);
}
Meteor.call("update-status", character._id, "");
},
});
所以现在数据库中的值是由事件设置的,UI是数据库中状态的表示。
注意:我已经简化了几件事,从内存中编写了代码,并从以前开始放弃了fadeIn
和fadeOut
的行为。
请根据您的需要编辑代码,我建议使用以下软件包制作动画:
gwendall:template-animations,或
gwendall:ui-hooks
答案 1 :(得分:1)
如果我理解正确,则希望与所有其他连接的客户端实时共享指标。这确实是流星可以轻松发光的功能类型。
您可能会错过的是,要使该功能正常工作,必须在MongoDB中提供要共享的数据/指示器,以便您的服务器随后可以将其实时推送给所有客户端(通过db进行此要求是必需的)有关Meteor服务器的设计方式,因此,即使瞬时指示符(如“写入状态”)也必须记录在db中。)
请参阅《流星》指南中的发布和订阅。