Что это такое и зачем оно нужно?
Бесконечная полоса прокрутки является распространенным элементом среди приложений, которые позволяют загружать небольшое количество элементов за раз, создавая впечатление плавного перемещения по элементам, чтобы предоставить пользователям беспроблемный опыт. Однако, в отличие от обычных бесконечных прокруток, которые добавляются к нижней части текущего содержимого, полосы прокрутки сообщений работают в противоположном направлении, т. е. приносят небольшое количество самых последних сообщений и добавляют их в начало отображаемых в данный момент сообщений.
Предпосылки
Шаги
- Добавьте следующее представление в views.py. Мы используем ListView, так как он заботится о нумерации страниц за нас. Мы можем просто отправить данные в формате json и вуаля, они станут конечной точкой API!
from django.http import Http404, JsonResponse, HttpResponse from django.shortcuts import render, get_object_or_404 from django.utils import timezone from django.views.generic import ListView from .models import Message, ConnectionEstablished class MessagesView(LoginRequiredMixin, ListView): paginate_by = 20 def get_queryset(self, *args, **kwargs): connection_established = ConnectionEstablished.objects.get( id=self.kwargs['connection_id'] ) queryset = Message.objects.filter( connection_established=connection_established ).order_by('-timestamp') return queryset def get(self, *args, **kwargs): # Validation and authentication connection = get_object_or_404( ConnectionEstablished, pk=kwargs['connection_id'] ) if self.request.user not in [connection.user1, connection.user2]: raise Http404("Chat not found") response = {} response['success'] = True paginator = self.get_paginator(self.get_queryset(), self.paginate_by) if int(self.request.GET.get('page', 1)) > paginator.num_pages: response['success'] = False return JsonResponse(response) template_response = super().get(*args, **kwargs) context_data = self.get_context_data() message_list = context_data['object_list'] message_json_list = [] for message in message_list: message_json = {} message_json['content'] = message.content message_json['timestamp'] = timezone.localtime( message.timestamp).strftime('%Y-%m-%d %H:%M') message_json['author'] = message.author.pk message_json_list.append(message_json) response['messages'] = message_json_list[::-1] return JsonResponse(response)
- Добавьте следующие фрагменты js в свой интерфейс (замените все идентификаторы и классы своими собственными)
Получить сообщения JS
<script> function scroll_top_load(page){ let messages_page = document.querySelector(`#messages-page-${page}`); if(messages_page){ messages_page.scrollIntoView(); } } //This function helps you scroll to the correct position once a new batch of messages are loaded. var page = 1 var observer = new IntersectionObserver(function(entries) { if(entries[0].isIntersecting === true){ url = ` {% url 'chat:get_messages' connection_id %}?page=${page} ` fetch(url, { method: "GET", headers: { "Content-type": "application/json; charset=UTF-8", }, }) .then((response) => { if (response.ok != true) { toastr.error(response.statusText); return null } else { return response.json() } }) .then(function (data) { if(data.success === true){ var add_messages = `` if(data.messages.length==0){ toastr.info('Start a conversation') } for(message of data.messages){ var add_message = draw_message(message,`scroll_top_load(${page})`) add_messages += add_message } add_messages += `<div id='messages-page-${page}'></div>`; let chat_box = document.querySelector('#chat-log'); chat_box.innerHTML = add_messages + chat_box.innerHTML; scroll_top_load(page++); } }) } observer.observe(document.querySelector("#message-loader")); }, { root: null }); observer.observe(document.querySelector("#message-loader")); </script>
- Обновите urls.py с помощью нового API.
urlpatterns += [ path('messages/<uuid:connection_id>/', views.MessagesView.as_view(), name='get_messages'), ]