Webflow单页作品集:优化多CMS视频播放器控制代码以避免重复
Hey there! Let's fix that repetitive code mess and make your player controls scalable—especially since your CMS is adding players dynamically. The key is to link each player to its corresponding button using shared parent containers and classes, instead of hardcoding IDs for every single pair.
Step 1: Adjust Your Webflow CMS Structure
First, make sure each video/button pair lives inside a shared container in your CMS collection item. Add these classes in Webflow:
- Give the collection item (or a wrapper around the button + player) a class like
.video-project - Keep your existing
.player_jsclass on the video element - Use a class (not an ID!) like
.play-btn(or keep.titre) for the play button (IDs will duplicate with CMS items, which is bad practice)
Your structure will look like this in rendered HTML:
<div class="video-project"> <button class="titre">Launch Video</button> <video class="player_js" src="your-video-url.mp4"></video> </div> <div class="video-project"> <button class="titre">Launch Another Video</button> <video class="player_js" src="another-video-url.mp4"></video> </div> <!-- CMS will repeat this block automatically -->
Step 2: Optimize the JavaScript (No More Repeat Code!)
Replace your repetitive player logic with this clean, scalable code. It will automatically handle any number of CMS-generated players—no need to edit code when you add new portfolio items.
Option 1: Direct Container Iteration (Simple & Reliable)
This loops through each project container and binds the button to its player directly:
<script src="https://cdn.plyr.io/3.5.6/plyr.js"></script> <script> document.addEventListener('DOMContentLoaded', () => { const controls = [ 'play-large','restart','play','progress', 'current-time','mute','volume','fullscreen' ]; // Initialize all players at once const players = Array.from(document.querySelectorAll('.player_js')) .map(p => new Plyr(p, { controls })); window.players = players; // Get all project containers and bind events to each pair document.querySelectorAll('.video-project').forEach((container, index) => { const playButton = container.querySelector('.titre'); const player = players[index]; // Play on button click playButton.addEventListener('click', () => player.play()); // Reset video when it ends player.on('ended', () => { player.pause(); player.currentTime = 0; }); }); }); </script>
Option 2: Event Delegation (Even Better for Dynamic Content)
If you ever add new projects dynamically (like via Webflow's "load more" feature), this version uses event delegation to handle buttons without rebinding events:
<script src="https://cdn.plyr.io/3.5.6/plyr.js"></script> <script> document.addEventListener('DOMContentLoaded', () => { const controls = [ 'play-large','restart','play','progress', 'current-time','mute','volume','fullscreen' ]; // Map video elements to their Plyr instances for quick lookup const playerMap = new Map(); const players = Array.from(document.querySelectorAll('.player_js')) .map(p => { const player = new Plyr(p, { controls }); playerMap.set(p, player); return player; }); window.players = players; // Handle play button clicks with event delegation document.addEventListener('click', (e) => { if (e.target.matches('.titre')) { const projectContainer = e.target.closest('.video-project'); const playerElement = projectContainer.querySelector('.player_js'); const player = playerMap.get(playerElement); if (player) player.play(); } }); // Reset all videos when they end players.forEach(player => { player.on('ended', () => { player.pause(); player.currentTime = 0; }); }); }); </script>
Why This Works
- No more repetition: One block of code handles every player/button pair
- CMS-friendly: Automatically adapts to new portfolio items added via your CMS
- Webflow character limit fix: This code is drastically shorter than writing 20+ duplicate blocks
- Maintainable: Easy to tweak the behavior (e.g., add a pause-all button later) without editing multiple lines
内容的提问来源于stack exchange,提问作者sprea

