我使用Vue.js构建了一个群聊消息。我目前正在获取返回如下数组的消息:
"data":[
{
"id":1,
"message":"<p>yo<\/p>",
"removed":"false",
"user":{
"uid":2,
"metadata":{
"username":"Testing"
}
},
"post_date":"2018-02-24 14:30"
},
{
"id":2,
"message":"<p>test<\/p>",
"removed":"false",
"user":{
"uid":1,
"metadata":{
"username":"Admin"
}
},
"post_date":"2018-02-24 22:31"
},
{
"id":3,
"message":"<p>Wassup?<\/p>",
"removed":"false",
"user":{
"uid":1,
"metadata":{
"username":"Admin"
}
},
"post_date":"2018-02-24 22:40"
},
{
"id":12,
"message":"again for testing post date",
"removed":"false",
"user":{
"uid":1,
"metadata":{
"username":"Admin"
}
},
"post_date":"2018-03-04 00:59"
},
{
"id":13,
"message":"Hello!",
"removed":"false",
"user":{
"uid":2,
"metadata":{
"username":"Testing"
}
},
"post_date":"2018-03-04 11:13"
},
{
"id":13,
"message":"<p>Hi!</p>",
"removed":"false",
"user":{
"uid":2,
"metadata":{
"username":"Testing"
}
},
"post_date":"2018-03-04 11:13"
},
],
目前,我只是循环访问数据并将每封邮件输出到单独的div
。我希望在同一个用户连续多次发布消息时对消息进行分组。
我该怎么做?它应该是一个选项服务器端(可能是一个可选的group
参数吗?)或以某种方式完成客户端?
如果我按UID /用户名对它们进行分组,问题是需要按顺序输出消息。因此,如果用户1发送三个消息,则用户2发送两个消息,然后用户1发送另一个消息,所有用户1消息将被分组在一起。相反,用户1的三个消息应该被分组,然后是用户2,然后它应该显示用户1的最后消息。
答案 0 :(得分:3)
我最近才为自己解决了这个问题。 这是full example。
在上面的示例中,用于分组消息的核心业务逻辑可以在src/store.js
函数的addMessage
下找到。
除非您的服务器还也存储所有消息,并且您有某种机制可以确保所有客户端之间的因果排序,否则我建议您在每个客户端上运行逻辑。这样,您可以确保客户在任何情况下都不会看到邮件跳来跳去。最糟糕的是,邮件将显示为未分组。
确定此消息的算法在收到新消息时运行,因此它在每个客户端上运行,但是您也可以对其进行调整以使其适合您的用例!如下所示(我可能使用了错误的流程图元素..歉意)。
addMessage({ state }, { msg, selfHash }) {
let addAsNewMsg = true;
const lastMessage = state.messages.slice(-1)[0];
if (lastMessage && lastMessage.userHash === msg.userHash) {
// The last message was also sent by the same user
// Check if it arrived within the grouping threshold duration (60s)
const lastMessageTime = moment(lastMessage.time);
const msgTime = moment(msg.time);
const diffSeconds = msgTime.diff(lastMessageTime, "seconds");
if (diffSeconds <= 60) {
addAsNewMsg = false; // We're going to be appending.. so
lastMessage.message.push(msg.message);
// We're going to now update the timestamp and (any) other fields.
delete msg.message; // Since, we've already added this above
Object.assign(lastMessage, msg); // Update with any remaining properties
}
}
if (addAsNewMsg) {
state.messages.push(msg);
}
}
答案 1 :(得分:1)
我的方法是保留对div的引用,该div包含最后一个用户的语音,以及一个表示最后一个要讲话的用户的uid的变量。当出现与最后一个uid匹配的消息时,您只需将其添加到要跟踪的div中;如果新的uid 不匹配,则只需创建一个新的div,将其添加到DOM中,然后更新uid变量即可。
// initialize variables
let lastUid,curDiv;
getData().forEach(msg => {
if (msg.user.uid !== lastUid) {
// new user is speaking!
curDiv = document.createElement("div");
document.body.appendChild(curDiv);
lastUid = msg.user.uid;
}
// add current message to the current div
curDiv.innerHTML += msg.message;
});
function getData() {
// really only put this in a function so that I could hoist it so that my logic can go above.
return [
{
"id":1,
"message":"<p>yo<\/p>",
"removed":"false",
"user":{
"uid":2,
"metadata":{
"username":"Testing"
}
},
"post_date":"2018-02-24 14:30"
},
{
"id":2,
"message":"<p>test<\/p>",
"removed":"false",
"user":{
"uid":1,
"metadata":{
"username":"Admin"
}
},
"post_date":"2018-02-24 22:31"
},
{
"id":3,
"message":"<p>Wassup?<\/p>",
"removed":"false",
"user":{
"uid":1,
"metadata":{
"username":"Admin"
}
},
"post_date":"2018-02-24 22:40"
},
{
"id":12,
"message":"again for testing post date",
"removed":"false",
"user":{
"uid":1,
"metadata":{
"username":"Admin"
}
},
"post_date":"2018-03-04 00:59"
},
{
"id":13,
"message":"Hello!",
"removed":"false",
"user":{
"uid":2,
"metadata":{
"username":"Testing"
}
},
"post_date":"2018-03-04 11:13"
},
{
"id":13,
"message":"<p>Hi!</p>",
"removed":"false",
"user":{
"uid":2,
"metadata":{
"username":"Testing"
}
},
"post_date":"2018-03-04 11:13"
},
]
}
div {
border: 1px solid black;
margin-bottom: 5px;
}
答案 2 :(得分:1)
似乎是计算属性的理想用例。首先按post_date
computed: {
sortedPosts() {
return this.posts.sort((a, b) => {
if (a.post_date < b.post_date) return -1;
else if (a.post_date > b.post_date) return +1;
return 0;
});
},
然后按user.uid
分组
groupedPosts() {
const posts = this.sortedPosts.reduce((post, grouped) => {
if (grouped.length === 0)
grouped.unshift([post]);
else if (grouped[0][0].user.uid === post.user.uid)
grouped[0].push(post);
else
grouped.unshift([post]);
return grouped;
}, []);
return posts.reverse();
}
然后在模板中使用了计算所得的属性
<div v-for="group in groupedPosts">
<div v-for="post in group">
(我尚未测试上面的代码,因此请注意输入错误等)
答案 3 :(得分:0)
您可以在服务器端按用户对邮件进行分组。
迭代数据,将每个对象推入数组对象,其中键是uid,值是相应用户的对象数组。
let dataByUser = {};
//Iterate over your data
for (let i = 0; i < data.length; i++) {
//If the object doesn't have a key equal to the current objects username,
//add it as a new key and set the values to a new array containing this datum.
if(!dataByUser.hasOwnProperty(data[i].user.uid) {
dataByUser[data[i].user.uid] = new Array(data[i]);
} else {
//If it does exist, push to the array for the existing key.
dataByUser[data[i].user.uid].push(data[i]);
}
}
你 应该以数据数组中每个用户的K:V对为对象,其中的值是包含所有相应消息的对象数组。
然后,您必须编写一些客户端代码,迭代这个新的数据结构并根据需要对其进行格式化。