动态视频播放的 JavaScript 脚本问题

问题描述 投票:0回答:1

`我的 JavaScript 脚本遇到了问题,该脚本本应管理我平台上的视频播放。目前,该脚本对于页面上已存在的视频元素可以正常工作,但它不考虑动态加载的新视频元素。所有脚本都不适用于这些新元素。

动态加载:当用户向下滚动时,视频通过 AJAX 添加到页面。 使用 IntersectionObserver:我尝试使用 IntersectionObserver 根据视频播放的可见性来启动或停止视频播放。

遇到的问题

No Playback for New Elements: When new video elements are loaded, the script does not work for these.
Complete Script Non-Functional: None of the script seems to function for these new elements.

如何确保脚本也适用于新加载的视频元素? 我是否应该遵循最佳实践来正确观察这些新元素?

我的js:

document.addEventListener('DOMContentLoaded', () => {
        let currentVideo = null;  
        const pulseContainer = document.getElementById('pulse-container');
        let currentPage = 1;
        let loading = false;
        let visibleVideoCount = 0;

        function handleVideoPlayback(entries) {
            entries.forEach(entry => {
                const video = entry.target;
                if (entry.isIntersecting) {
                    if (currentVideo !== video) {
                        video.play();
                        video.loop = true;
                        if (currentVideo) {
                            currentVideo.pause();
                        }
                        currentVideo = video;
                    }
                    visibleVideoCount++;
                    console.log(visibleVideoCount);
                } else {
                    if (currentVideo === video) {
                        currentVideo = null;  
                    }
                    video.pause();
                }
            });
    
            // Vérifiez si le compteur de vidéos visibles atteint 5
            if (visibleVideoCount >= 5) {
                console.log('loadmore please');
                loadMoreContent(); // Charge plus de contenu
                visibleVideoCount = 0; // Réinitialise le compteur
            }
        }  
    
        const observer = new IntersectionObserver(handleVideoPlayback, {
            root: null,
            rootMargin: '0px',
            threshold: 0.5
        });
    
        const videos = document.querySelectorAll('.pulse-video');
        videos.forEach(video => {
            observer.observe(video);
            video.addEventListener('error', (e) => {
                console.error('Erreur de chargement de la vidéo:', e);
            });
            video.src = video.getAttribute('data-src');
            video.load();
           
        });
    
        function toggleGlobalSound() {
            const newMutedState = !Array.from(videos).some(video => video.muted);
            videos.forEach(video => {
                video.muted = newMutedState;
            });
            const globalSoundButtons = document.querySelectorAll('#global-sound-toggle i');
            globalSoundButtons.forEach(icon => {
                icon.classList.toggle('fa-volume-xmark', newMutedState);
                icon.classList.toggle('fa-volume-high', !newMutedState);
            });
        }
        
        const globalSoundButtons = document.querySelectorAll('#global-sound-toggle');
        globalSoundButtons.forEach(button => {
            button.addEventListener('click', toggleGlobalSound);
        });
    
        function setupVideoClickHandler() {
            const videos = document.querySelectorAll('.pulse-video'); // Récupère les vidéos à chaque appel
            videos.forEach(video => {
                video.addEventListener('click', () => {
                    video.paused ? video.play() : video.pause();
                    if (currentVideo && currentVideo !== video) {
                        currentVideo.pause();
                    }
                    currentVideo = video;
                });
            });
        }
    
        function handleVisibilityChange() {
            if (document.hidden && currentVideo) {
                currentVideo.pause();
            } else if (!document.hidden && currentVideo) {
                currentVideo.play();
            }
            
        }
        const artistContents = document.querySelectorAll('.artist-content');

        artistContents.forEach(content => {
            const toggleButton = content.querySelector('.toggle-description');

            if (toggleButton) {
                toggleButton.addEventListener('click', () => {
                    content.classList.toggle('open');
                });
            }
        });
        const allArtistElements = document.querySelectorAll('.all_artist'); // Pour plusieurs artistes
        
        allArtistElements.forEach(function(artistContent) {
            const toggleButton = artistContent.querySelector('.toggle-description');
            const descriptionContent = artistContent.querySelector('.description-content');
            
            // Fonction pour ajuster la hauteur de .all_artist.open
            function adjustHeight() {
                const descriptionHeight = descriptionContent.scrollHeight; // Hauteur réelle du contenu
                const additionalHeight = 0; // Hauteur supplémentaire pour que ça monte plus
                artistContent.style.height = `${descriptionHeight + additionalHeight}px`; // Ajuste la hauteur en fonction du contenu
                artistContent.style.transform = `translateY(-${descriptionHeight + additionalHeight}px)`; 
            }
            
            // Fonction pour ouvrir et fermer le contenu
            function toggleArtistContent() {
                artistContent.classList.toggle('open');
                if (artistContent.classList.contains('open')) {
                    descriptionContent.style.transform = 'translateY(0)'; // Annule le translateY
                    descriptionContent.style.opacity = '1'; // Affiche le contenu
                    descriptionContent.style.visibility = 'visible'; // Rend le contenu visible
                    adjustHeight(); // Ajuste la hauteur de .all_artist.open
                } else {
                    descriptionContent.style.transform = 'translateY(-50px)'; // Cache l'élément
                    descriptionContent.style.opacity = '0'; // Rend le contenu invisible
                    descriptionContent.style.visibility = 'hidden'; // Cache le contenu
                    artistContent.style.height = 'auto'; // Réinitialise la hauteur
                    artistContent.style.transform = `translateY(0)`; // Réinitialise la position
                }
            }
            
            // Écouteur d'événement sur le bouton pour basculer l'affichage
            toggleButton.addEventListener('click', toggleArtistContent);
        });
    
        document.addEventListener('visibilitychange', handleVisibilityChange);
    
        function adjustVideoSize() {
            videos.forEach(video => {
                video.style.width = '100%';
                video.style.height = '100%';
                video.style.objectFit = 'cover';
            });
        }
    
        function preloadVideos() {
            const videos = document.querySelectorAll('.pulse-video'); // Récupère les vidéos à chaque appel
            videos.forEach(video => {
                const rect = video.getBoundingClientRect();
                if (rect.top < window.innerHeight && rect.bottom > 0) {
                    if (video.src === '') {
                        video.src = video.getAttribute('data-src');
                        video.load();
                    }
                }
                observer.observe(video); // Assure-toi que chaque vidéo est observée
            });
        }
        const loadMoreUrl = '/pulses/load-more-pulses/';
        function loadMoreContent() {
            console.log('Trying to load more content...');
            if (loading) return;
            loading = true;
    
            const url = `/pulses/load-more-pulses/?page=${currentPage}`;
            fetch(url)
                .then(response => {
                    console.log('Response status:', response.status);
                    if (!response.ok) {
                        throw new Error('Network response was not ok');
                    }
                    return response.json();
                })
                .then(data => {
                    console.log('Data received:', data);
                    if (data.pulse_data) {
                        data.pulse_data.forEach(pulse => {
                            pulseContainer.insertAdjacentHTML('beforeend', pulse.html);
                        });
                        currentPage++;
                        initializeNewElements()
                       
                    }
                })
                .catch(error => {
                    console.error('Error loading more content:', error);
                })
                .finally(() => {
                    loading = false;
                });
        }
    
        // Appelle les fonctions au chargement initial
        preloadVideos();
        
       
    
        function setupInteractionButtons() {
            const likeButtons = document.querySelectorAll('.like-button');
            const shareButtons = document.querySelectorAll('.share-button');
    
            likeButtons.forEach(button => {
                button.addEventListener('click', () => {
                    const pulseId = button.dataset.pulseId;
                    fetch('{% url "pulses:toggle_like" %}', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/x-www-form-urlencoded',
                            'X-CSRFToken': getCookie('csrftoken')
                        },
                        body: new URLSearchParams({ 'pulse_id': pulseId })
                    })
                    .then(response => response.json())
                    .then(data => {
                        if (data.error) {
                            alert(data.error);
                        } else {
                            button.querySelector('i').classList.toggle('fa-solid', data.liked);
                            button.querySelector('i').classList.toggle('fa-regular', !data.liked);
                            button.querySelector('i').style.color = data.liked ? '#d20000' : 'floralwhite';
                            button.querySelector('.like-count').textContent = data.like_count;
                        }
                    })
                    .catch(error => console.error('Error:', error));
                });
            });
    
            shareButtons.forEach(button => {
                button.addEventListener('click', () => {
                    const pulseId = button.dataset.pulseId;
                    fetch('{% url "pulses:share_pulse" %}', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                            'X-CSRFToken': getCookie('csrftoken')
                        },
                        body: JSON.stringify({ pulse_id: pulseId })
                    })
                    .then(response => response.json())
                    .then(data => {
                        if (data.success) {
                            document.querySelector(`.share-count[data-pulse-id="${pulseId}"]`).textContent = data.share_count;
                            navigator.clipboard.writeText(data.share_url)
                                .then(() => {
                                    alert('Lien copié!');
                                })
                                .catch(err => {
                                    console.error('Erreur lors de la copie du lien:', err);
                                });
                        }
                    })
                    .catch(error => console.error('Error:', error));
                });
            });
        }
    
        document.querySelectorAll('.toggle-comments').forEach(button => {
            button.addEventListener('click', () => {
                const commentsSection = button.closest('.pulse_item').querySelector('.comments-section');
                commentsSection.style.display = commentsSection.style.display === 'none' || commentsSection.style.display === '' ? 'flex' : 'none';
            });
        });
    
        setupVideoClickHandler();
        setupInteractionButtons();
        adjustVideoSize();
        preloadVideos();
    });
    
    function getCookie(name) {
        let cookieValue = null;
        if (document.cookie && document.cookie !== '') {
            const cookies = document.cookie.split(';');
            for (let cookie of cookies) {
                cookie = cookie.trim();
                if (cookie.substring(0, name.length + 1) === (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }


    function loadScript(scriptUrl) {
        const script = document.createElement('script');
        script.src = scriptUrl;
        script.type = 'text/javascript';
        document.body.appendChild(script);
    }
    
    
    function initializeNewElements() {
        const videos = document.querySelectorAll('.pulse-video');
        if (!videos.length) return; // Vérification de la présence de vidéos
    
        videos.forEach(video => {
            observer.observe(video);
        });
        
        setupInteractionButtons(); // Ajouter les interactions aux nouveaux boutons
    }
 

我的全局 html :

   <div class="all_pulse">
    <div class="pulse_title">Pulse</div>
    <div class="pulse_contains" id="pulse-container">
        {% for pulse in pulses %}
            {% include 'pages/partial-pulse.html' with pulse=pulse %}
        {% endfor %}
    </div>
    <div class="bar">
        <div class="bar-item">
            <a href="{% url 'content:index' %}" style="color:white;"><i class="fa-solid fa-house"></i></a>
            <a href="{% url 'beats:new_explore' %}" style="color:white;"><i class="fa-solid fa-magnifying-glass"></i></a>
            <a href="{% url 'pulses:pulse' %}" style="color:white;"><i class="fa-solid fa-compact-disc fa-lg" style="margin-top:5.5px;"></i></a>
            <a href="{% url 'accounts:conversations' %}" style="color:white;"><i class="fa-solid fa-message"></i></a>
            <a href="{% url 'accounts:profile' %}" style="color:white;"><i class="fa-solid fa-user"></i></a>
        </div>
    </div>
</div>   

我的HTML是用ajax实现的:

{% load static %}
<script src="{% static 'js/new_pulse.js' %}"></script>
<div class="pulse_item">
    <div class="video-wrapper">
        <video data-src="{{ pulse.video.url }}" class="pulse-video" src="{{ pulse.video.url }}"   muted playsinline></video>
        
    </div>
    <div class="comments-section" style="display: none;">
        <div class="comment-list">
            <h5 class="title_comments">Comments</h5>
            {% if pulse.comments.all %}
                {% for comment in pulse.comments.all %}
                    <div class="comment">
                        <strong>{{ comment.user.username }}:</strong>
                        <p>{{ comment.text }}</p>
                        <small style="color:grey;">{{ comment.created_at|date:"d M Y, H:i" }}</small>
                    </div>
                {% endfor %}
            {% else %}
                <p style="color:white;">Aucun commentaire</p>
            {% endif %}
         </div>
        <textarea class="comment-input" placeholder="Écrivez un commentaire..."></textarea>
        <button class="button-up" data-pulse-id="{{ pulse.id }}">Envoyer</button>
        
    </div>
    <div class="interacts">
        <div class="item-orga">
            
            <button class="like-button" data-pulse-id="{{ pulse.id }}" style="background-color:transparent;color:white;border:none;">
                <i class="fa-heart {% if pulse.liked %}fa-solid{% else %}fa-regular{% endif %} fa-xl" style="color: {% if pulse.liked %}#d20000{% else %}floralwhite{% endif %}; margin-right: 4px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);"></i>
                <span class="like-count">{% if pulse.like_count %}{{ pulse.like_count }}{% else %}0{% endif %}</span>
            </button>
            <button class="share-button" data-pulse-id="{{ pulse.id }}" style="background-color:transparent;color:white;border:none;">
                <i class="fa-solid fa-share fa-xl" style="color:floralwhite;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);"></i>
                <span class="share-count" data-pulse-id="{{ pulse.id }}">{% if pulse.share_count %}{{ pulse.share_count }}{% else %}0{% endif %} </span>
            </button>
            <button class="comments-button" data-pulse-id="{{ pulse.id }}" style="background-color:transparent;color:white;border:none;">
            <i class="fa-solid fa-comments fa-xl toggle-comments" style="color:floralwhite;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);"></i>
            <span class="comments_count" data-pulse-id="{{ pulse.id }}">{% if pulse.comments %}{{ pulse.comments_count }}{% else %}0{% endif %} </span>
            </button>
            <button id="global-sound-toggle"><i class="fa-solid fa-volume-xmark" style="color:floralwhite;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);"></i></button>
        </div>
    </div>
    
    <div class="data_artist">
        <div class="all_artist">
            <div class="artist-content">
                <div class="profile_picture_pulse">
                    {% if pulse.user.profile_picture %}
                        <img src="{{ pulse.user.profile_picture.url }}" class="img-fluid rounded-circle" style="min-width: 50px;max-width: 50px; height: 50px;" alt="Profile Picture">
                    {% else %}
                        <img src='/static/images/default_profile.png' class="img-fluid rounded-circle" style="width: 50px; height: 50px;" alt="Profile Picture">
                    {% endif %}
                </div>
                <div class="username_pulse">
                    <strong> <p id="superstrong" style="margin-bottom:0;">{{ pulse.user.username }} </p></strong>
                    
                    {% if request.user != pulse.user %}
                        <button id="sub_pulse"
                        class="follow-toggle-btn btn-style-2 {% if is_followed %}btn-yes{% else %}btn-no{% endif %}"
                            data-user-id="{{ pulse.user.id }}"
                        >
                            {% if is_followed %}Unfollow{% else %}Follow{% endif %}
                        </button>
                        <span style="margin-left:5px;" class="follower-count">{{ pulse.follower_count }}</span>
                        <input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">
                    {% endif %}
                    
                    <button class="toggle-description" aria-label="Show description">
                        <i class="fa-solid fa-chevron-down"></i>
                    </button>
                </div>
            </div>
            
            
            
            
            
            <div class="description-content">
                <p class="description-text">
                    {{ pulse.description }}<span class="more-text">{{ pulse.description|slice:"100:" }}</span>
                    {% for hashtag in pulse.hashtags.all %}
                    <a href="" alt="{{hashtag.name}}"style="text-decoration:none;">#{{hashtag}} </a>
                    {% endfor %}
                </p>
                
            </div>
        </div>
   

        
        <div class="song-content">
            <div class="song_pulse">
                <img src="/static/images/explore.webp" alt="Cover" class="square-image-x-fill beat-icon-beat_detail">
            </div>
        </div>
    </div>
    
</div>`
javascript html ajax dynamic-content
1个回答
0
投票

您应该在新内容加载并附加到 DOM 后调用initializeNewElements。您可以在收到新内容并将其附加到脉冲容器后,在 loadMoreContent 函数中执行此操作。

以下是如何修改 loadMoreContent 函数以在加载新内容后调用initializeNewElements:

function loadMoreContent() {
    console.log('Trying to load more content...');
    if (loading) return;
    loading = true;

    const url = `/pulses/load-more-pulses/?page=${currentPage}`;
    fetch(url)
        .then(response => {
            console.log('Response status:', response.status);
            if (!response.ok) {
                throw new Error('Network response was not ok');
            }
            return response.json();
        })
        .then(data => {
            console.log('Data received:', data);
            if (data.pulse_data) {
                data.pulse_data.forEach(pulse => {
                    pulseContainer.insertAdjacentHTML('beforeend', 
pulse.html);
                });
                currentPage++;
                initializeNewElements(); // Call initializeNewElements 
after new content is loaded
            }
        })
        .catch(error => {
            console.error('Error loading more content:', error);
        })
        .finally(() => {
            loading = false;
        });
}

此外,您还应该在initializeNewElements函数中观察新的视频元素。您已经这样做了,但您还应该为新视频元素添加事件侦听器。以下是您可以修改initializeNewElements函数以添加新视频元素的事件侦听器的方法:

function initializeNewElements() {
const videos = document.querySelectorAll('.pulse-video');
if (!videos.length) return; // Vérification de la présence de vidéos

videos.forEach(video => {
    observer.observe(video); // Observe the new video elements
    video.addEventListener('error', (e) => {
        console.error('Erreur de chargement de la vidéo:', e);
    });
    video.src = video.getAttribute('data-src');
    video.load();
});

 setupInteractionButtons(); // Ajouter les interactions aux nouveaux 
 boutons
 setupVideoClickHandler(); // Add event listeners for the new video 
 elements
}
© www.soinside.com 2019 - 2024. All rights reserved.