Вопрос или проблема
Я создал веб-сайт на Firebase с использованием JS и фронтенда
Все работает правильно, за исключением одной вещи. Мои чаты не сортируются по дате корректно
Вот что я вижу сейчас:
Anastasia: Привет! (9/17/2024, 10:46:47 PM)
Anastasia: Как дела? (9/17/2024, 10:47:06 PM)
Anastasia: Привет (9/17/2024, 11:41:27 PM)
User2: Да (9/17/2024, 10:49:16 PM)
User2: Хорошо, спасибо! (9/17/2024, 10:47:23 PM)
User2: Привет (9/17/2024, 10:46:55 PM)
Что я хочу видеть:
User2: Привет (9/17/2024, 10:46:55 PM)
Anastasia: Привет! (9/17/2024, 10:46:47 PM)
Anastasia: Как дела? (9/17/2024, 10:47:06 PM)
User2: Хорошо, спасибо! (9/17/2024, 10:47:23 PM)
User2: Да (9/17/2024, 10:49:16 PM)
Anastasia: Привет (9/17/2024, 11:41:27 PM)
Мой код
document.addEventListener("DOMContentLoaded", () => {
firebase.auth().onAuthStateChanged((user) => {
if (user) {
const chatId = new URLSearchParams(window.location.search).get("chatId");
if (!chatId) {
console.error("Недействительный или отсутствующий chatId в URL.");
return;
}
// Извлечение сообщений в порядке по временной метке
const messagesRefForDisplay = firebase
.database()
.ref(`chats/${chatId}/messages`)
.orderByChild("timestamp");
// Используйте обычную ссылку для отправки сообщений
const messagesRefForSending = firebase
.database()
.ref(`chats/${chatId}/messages`);
// Функция для получения имени пользователя по ID пользователя
function getUsername(userId, callback) {
const userRef = firebase.database().ref(`users/${userId}`);
userRef.once("value", (snapshot) => {
const userData = snapshot.val();
callback(userData.username);
});
}
function formatTimestamp(timestamp) {
const date = new Date(timestamp);
return date.toLocaleString(); // Настройте формат при необходимости
}
// Загружаем сообщения в порядке по временной метке
messagesRefForDisplay.on("child_added", (snapshot) => {
const message = snapshot.val();
getUsername(message.senderId, (username) => {
const messageElement = document.createElement("div");
messageElement.classList.add("message");
const formattedTimestamp = formatTimestamp(message.timestamp);
messageElement.innerHTML = `<span class="sender">${username}:</span> ${message.message} <span class="timestamp">(${formattedTimestamp})</span>`;
document.getElementById("messages").appendChild(messageElement);
// Автопрокрутка вниз после добавления нового сообщения
document.getElementById("messages").scrollTop =
document.getElementById("messages").scrollHeight;
});
});
// Отправка сообщения
document.getElementById("sendMessage").addEventListener("click", () => {
const messageInput = document.getElementById("messageInput");
const messageText = messageInput.value.trim();
if (messageText) {
// Используйте необработанную ссылку messagesRef для отправки
messagesRefForSending
.push({
message: messageText,
senderId: user.uid, // Используйте user.uid здесь
timestamp: Date.now(),
})
.then(() => {
console.log("Сообщение успешно отправлено");
})
.catch((error) => {
console.error("Ошибка при отправке сообщения:", error);
});
messageInput.value = ""; // Очистить поле ввода
}
});
} else {
console.log("Пользователь не вошёл в систему.");
}
});
});
Ответ или решение
Для решения проблемы с неправильным порядком сообщений в Firebase, нужно обратить внимание на процесс, который мы используем для отображения сообщений. В вашем текущем коде вы добавляете сообщения в порядок, определяемый Firebase, который может не всегда совпадать с временными метками, особенно если сообщения приходят в разное время.
Проблема
Сообщения выводятся на экран по мере их добавления, и это может привести к неправильному порядку, как в вашем примере. Чтобы исправить это, нужно сначала собрать все сообщения, отсортировать их по временной метке и только затем отобразить.
Решение
Предлагаю следующий алгоритм:
- Получите все сообщения из Firebase с сортировкой по временной метке используя
once("value")
вместоon("child_added")
. Это позволит вам получить все сообщения сразу. - Сохраните их в массив.
- Отсортируйте массив по временной метке.
- После сортировки отобразите сообщения на экране.
Модификация вашего кода
Вот как можно изменить ваш код:
document.addEventListener("DOMContentLoaded", () => {
firebase.auth().onAuthStateChanged((user) => {
if (user) {
const chatId = new URLSearchParams(window.location.search).get("chatId");
if (!chatId) {
console.error("Неверный или отсутствующий chatId в URL.");
return;
}
// Ссылка на сообщения
const messagesRef = firebase.database().ref(`chats/${chatId}/messages`);
// Функция для получения имени пользователя
function getUsername(userId, callback) {
const userRef = firebase.database().ref(`users/${userId}`);
userRef.once("value", (snapshot) => {
const userData = snapshot.val();
callback(userData.username);
});
}
function formatTimestamp(timestamp) {
const date = new Date(timestamp);
return date.toLocaleString(); // Можно настроить формат
}
// Получение сообщений, сортировка и отображение
messagesRef.once("value", (snapshot) => {
const messages = [];
snapshot.forEach((childSnapshot) => {
const message = childSnapshot.val();
messages.push({
...message,
key: childSnapshot.key // Сохраняем ключ сообщения для дальнейшего использования, если потребуется
});
});
// Сортируем сообщения по временной метке
messages.sort((a, b) => a.timestamp - b.timestamp);
// Отображаем сообщения
messages.forEach((message) => {
getUsername(message.senderId, (username) => {
const messageElement = document.createElement("div");
messageElement.classList.add("message");
const formattedTimestamp = formatTimestamp(message.timestamp);
messageElement.innerHTML = `<span class="sender">${username}:</span> ${message.message} <span class="timestamp">(${formattedTimestamp})</span>`;
document.getElementById("messages").appendChild(messageElement);
});
});
// Автоскроллинг вниз после загрузки всех сообщений
document.getElementById("messages").scrollTop =
document.getElementById("messages").scrollHeight;
});
// Отправка сообщения
document.getElementById("sendMessage").addEventListener("click", () => {
const messageInput = document.getElementById("messageInput");
const messageText = messageInput.value.trim();
if (messageText) {
messagesRef.push({
message: messageText,
senderId: user.uid,
timestamp: Date.now(),
})
.then(() => {
console.log("Сообщение успешно отправлено");
messageInput.value = ""; // Очистить ввод
})
.catch((error) => {
console.error("Ошибка при отправке сообщения:", error);
});
}
});
} else {
console.log("Пользователь не авторизован.");
}
});
});
Объяснение изменений:
- Получение всех сообщений: Использование
once("value")
вместоon("child_added")
собирает все сообщения сразу. - Сортировка сообщений: После получения всех сообщений мы сортируем массив сообщений по временной метке.
- Отображение сообщений: После сортировки сообщения отображаются в верном порядке.
- Автоскроллинг: После отображения всех сообщений добавляется автоскроллинг вниз.
Эти изменения должны исправить проблему с порядком сообщений в вашем приложении. Надеюсь, это поможет! Если у вас есть другие вопросы, не стесняйтесь спрашивать.