fix: scroll chat usa Livewire.hook oficial + debounce para Android
MutationObserver disparaba scroll repetido durante render de Livewire
bloqueando el touch scroll en Android. Ahora usa Livewire.hook('message.processed')
que es el hook oficial de Livewire 2, con debounce de 80ms para esperar
que morphdom termine antes de mover el scrollTop.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
d77eabc272
commit
7cc696e04a
@@ -605,39 +605,58 @@
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
function initChatScroll() {
|
||||
const container = document.getElementById('pub-messages');
|
||||
const badge = document.getElementById('new-msg-badge');
|
||||
const badgeBtn = document.getElementById('new-msg-badge-btn');
|
||||
const countEl = document.getElementById('new-msg-count');
|
||||
var container, badge, badgeBtn, countEl;
|
||||
var userScrolledUp = false;
|
||||
var newMsgCount = 0;
|
||||
var debounceTimer = null;
|
||||
|
||||
function atBottom() {
|
||||
return container.scrollHeight - container.scrollTop - container.clientHeight < 120;
|
||||
}
|
||||
|
||||
function scrollToBottom() {
|
||||
container.scrollTop = container.scrollHeight;
|
||||
}
|
||||
|
||||
function showBadge(n) {
|
||||
if (!badge || !countEl) return;
|
||||
countEl.textContent = n;
|
||||
badge.classList.remove('hidden');
|
||||
badge.classList.add('flex');
|
||||
}
|
||||
|
||||
function hideBadge() {
|
||||
if (!badge) return;
|
||||
badge.classList.add('hidden');
|
||||
badge.classList.remove('flex');
|
||||
newMsgCount = 0;
|
||||
}
|
||||
|
||||
function onUpdate() {
|
||||
if (!userScrolledUp) {
|
||||
scrollToBottom();
|
||||
} else {
|
||||
newMsgCount++;
|
||||
showBadge(newMsgCount);
|
||||
}
|
||||
}
|
||||
|
||||
function debouncedUpdate() {
|
||||
clearTimeout(debounceTimer);
|
||||
debounceTimer = setTimeout(onUpdate, 80);
|
||||
}
|
||||
|
||||
document.addEventListener('livewire:load', function () {
|
||||
container = document.getElementById('pub-messages');
|
||||
badge = document.getElementById('new-msg-badge');
|
||||
badgeBtn = document.getElementById('new-msg-badge-btn');
|
||||
countEl = document.getElementById('new-msg-count');
|
||||
if (!container) return;
|
||||
|
||||
let userScrolledUp = false;
|
||||
let newMsgCount = 0;
|
||||
let lastScrollHeight = container.scrollHeight;
|
||||
|
||||
function atBottom() {
|
||||
return container.scrollHeight - container.scrollTop - container.clientHeight < 120;
|
||||
}
|
||||
|
||||
function scrollToBottom() {
|
||||
container.scrollTop = container.scrollHeight;
|
||||
}
|
||||
|
||||
function showBadge(n) {
|
||||
if (!badge || !countEl) return;
|
||||
countEl.textContent = n;
|
||||
badge.classList.remove('hidden');
|
||||
badge.classList.add('flex');
|
||||
}
|
||||
|
||||
function hideBadge() {
|
||||
if (!badge) return;
|
||||
badge.classList.add('hidden');
|
||||
badge.classList.remove('flex');
|
||||
newMsgCount = 0;
|
||||
}
|
||||
// Scroll inicial
|
||||
scrollToBottom();
|
||||
|
||||
// Click en badge baja al fondo
|
||||
if (badgeBtn) {
|
||||
badgeBtn.addEventListener('click', function () {
|
||||
container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' });
|
||||
@@ -645,6 +664,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
// Detectar scroll manual del usuario
|
||||
container.addEventListener('scroll', function () {
|
||||
if (atBottom()) {
|
||||
userScrolledUp = false;
|
||||
@@ -654,32 +674,10 @@
|
||||
}
|
||||
}, { passive: true });
|
||||
|
||||
// Scroll inicial al fondo
|
||||
scrollToBottom();
|
||||
|
||||
// MutationObserver: detecta cuando Livewire agrega/modifica nodos en el contenedor
|
||||
const observer = new MutationObserver(function () {
|
||||
const newHeight = container.scrollHeight;
|
||||
if (newHeight === lastScrollHeight) return;
|
||||
lastScrollHeight = newHeight;
|
||||
|
||||
if (!userScrolledUp) {
|
||||
scrollToBottom();
|
||||
} else {
|
||||
newMsgCount++;
|
||||
showBadge(newMsgCount);
|
||||
}
|
||||
// Hook oficial Livewire 2: se ejecuta después de cada update del componente
|
||||
Livewire.hook('message.processed', function (message, component) {
|
||||
debouncedUpdate();
|
||||
});
|
||||
|
||||
observer.observe(container, { childList: true, subtree: true });
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initChatScroll);
|
||||
} else {
|
||||
initChatScroll();
|
||||
}
|
||||
|
||||
document.addEventListener('livewire:load', initChatScroll);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user