admin管理员组文章数量:1278984
I have a group chat message build using Vue.js. I am currently fetching the messages which returns an array like this:
"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"
},
],
At the moment I am just looping through the data and outputting each message into a separate div
. What I would prefer is to group the messages when the same user has posted more than once in a row.
How would I go about this? Should it be an option server side (maybe an optional group
parameter?) or somehow done client side?
EDIT This is how the chat current looks:
And this is the desired look:
The problem if I group them by the UID/Username, is that the messages need to be output in order. So if User 1 send three messages, then User 2 send two, then User 1 sends another message, all of user 1s message will be grouped together. Rather the User 1s three messages should be grouped, then User 2s, then it should show User 1s last message.
I have a group chat message build using Vue.js. I am currently fetching the messages which returns an array like this:
"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"
},
],
At the moment I am just looping through the data and outputting each message into a separate div
. What I would prefer is to group the messages when the same user has posted more than once in a row.
How would I go about this? Should it be an option server side (maybe an optional group
parameter?) or somehow done client side?
EDIT This is how the chat current looks:
And this is the desired look:
The problem if I group them by the UID/Username, is that the messages need to be output in order. So if User 1 send three messages, then User 2 send two, then User 1 sends another message, all of user 1s message will be grouped together. Rather the User 1s three messages should be grouped, then User 2s, then it should show User 1s last message.
Share Improve this question edited Mar 4, 2018 at 12:06 asked Mar 4, 2018 at 11:43 user7856768user7856768 1- Can you give an example of what you want the output to look like? – Roy J Commented Mar 4, 2018 at 11:49
4 Answers
Reset to default 4 +25I solved this problem for myself pretty recently. Here's a full example.
The core business logic for grouping messages, in the above example, can be found under src/store.js
in the addMessage
function.
Unless your server is also storing all the messages and you have some mechanism to ensure causal ordering across all clients, I would remend that you run the logic on each client. That way, you ensure that clients don't see messages jumping around under any circumstance. At worst, messages would appear ungrouped.
The algorithm to determine this is run when a new message is received, therefore it runs on each client, but you can tweak it to work for your use-case as well! It's shown below (I may have used the wrong flowchart elements..apologies).
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);
}
}
Seems like an ideal use case for puted properties. First sort the data by post_date
puted: {
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;
});
},
Then group by 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();
}
Then used the puted property in a template
<div v-for="group in groupedPosts">
<div v-for="post in group">
(I haven't tested the code above, so watch for typos, etc.)
My approach would be to keep a reference to the div containing the last user's speech, and a variable representing the uid of the last user to speak. When a message es in that matches the last uid, you'll simply add it to the div you're keeping track of; if the new uid doesn't match the previous one, you'll simply create a new div, add it to the DOM, and update the uid variable.
// 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;
}
You could group your messages by user on the server-side.
Iterate over the data, pushing each object into an object of arrays, where the keys are the uid's and the values are arrays of objects for the respective user.
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]);
}
}
You should end up with an object with a K:V pair per user in your data array, where their values are arrays of objects with all the respective messages in.
You'd then have to write some client code that iterates over this new data structure and formats it however you wish.
本文标签: javascriptHow to group chat messages per userStack Overflow
版权声明:本文标题:javascript - How to group chat messages per user? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741291052a2370549.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论