Что это такое и зачем оно нужно?

Бесконечная полоса прокрутки является распространенным элементом среди приложений, которые позволяют загружать небольшое количество элементов за раз, создавая впечатление плавного перемещения по элементам, чтобы предоставить пользователям беспроблемный опыт. Однако, в отличие от обычных бесконечных прокруток, которые добавляются к нижней части текущего содержимого, полосы прокрутки сообщений работают в противоположном направлении, т. е. приносят небольшое количество самых последних сообщений и добавляют их в начало отображаемых в данный момент сообщений.

Предпосылки

Шаги

  • Добавьте следующее представление в 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'),
]

Статьи по Теме