如何在Node.js+Express项目中实现Pexels API分页加载视频
Here's a step-by-step implementation to add paginated loading via a button to your Node.js + Express + EJS app:
1. Backend: Add an API Endpoint for Paginated Videos
First, we'll create a dedicated API route that accepts a page parameter and returns video data as JSON. This lets us fetch new pages without reloading the entire page.
Update app.js:
If using the official Pexels npm package:
const express = require('express'); const app = express(); const { createClient } = require('pexels'); require('dotenv').config(); // Store API keys securely with dotenv const pexelsClient = createClient(process.env.PEXELS_API_KEY); // Initial homepage route (renders first page of videos) app.get('/', async (req, res) => { try { const response = await pexelsClient.videos.search({ query: 'nature', page: 1, per_page: 8 }); res.render('index', { videos: response.videos, totalResults: response.total_results // Pass total count to frontend }); } catch (err) { console.error('Error fetching initial videos:', err); res.render('index', { videos: [], totalResults: 0 }); } }); // New API route for fetching additional pages app.get('/api/videos', async (req, res) => { try { const page = parseInt(req.query.page) || 1; const response = await pexelsClient.videos.search({ query: 'nature', page: page, per_page: 8 }); res.json({ videos: response.videos, totalResults: response.total_results }); } catch (err) { console.error('Error fetching videos via API:', err); res.status(500).json({ error: 'Failed to load videos' }); } }); app.listen(3000, () => console.log('Server running on port 3000'));
If using raw fetch (no npm package):
const express = require('express'); const app = express(); const fetch = require('node-fetch'); // Use native fetch in Node.js 18+ require('dotenv').config(); const PEXELS_API_KEY = process.env.PEXELS_API_KEY; const PEXELS_VIDEO_URL = 'https://api.pexels.com/videos/search'; app.get('/', async (req, res) => { try { const response = await fetch(`${PEXELS_VIDEO_URL}?query=nature&page=1&per_page=8`, { headers: { Authorization: PEXELS_API_KEY } }); const data = await response.json(); res.render('index', { videos: data.videos, totalResults: data.total_results }); } catch (err) { console.error('Error:', err); res.render('index', { videos: [], totalResults: 0 }); } }); app.get('/api/videos', async (req, res) => { try { const page = parseInt(req.query.page) || 1; const response = await fetch(`${PEXELS_VIDEO_URL}?query=nature&page=${page}&per_page=8`, { headers: { Authorization: PEXELS_API_KEY } }); const data = await response.json(); res.json({ videos: data.videos, totalResults: data.total_results }); } catch (err) { res.status(500).json({ error: 'Failed to load videos' }); } }); app.listen(3000, () => console.log('Server running on port 3000'));
Important: Store your Pexels API key in a .env file (never hardcode it!) and install dotenv via npm install dotenv.
2. Frontend: Add "Show More" Button & AJAX Logic
Update your index.ejs to include the button and JavaScript that fetches new pages and appends videos to the DOM.
index.ejs:
<!DOCTYPE html> <html> <head> <title>Nature Videos</title> <style> .videos-container { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 20px; margin-bottom: 20px; padding: 0 20px; } .video-card { border: 1px solid #eee; border-radius: 8px; overflow: hidden; transition: transform 0.2s; } .video-card:hover { transform: translateY(-5px); } .video-card img { width: 100%; height: 180px; object-fit: cover; } .video-card p { padding: 10px; margin: 0; font-size: 14px; color: #333; } #show-more-btn { display: block; margin: 0 auto 30px; padding: 10px 20px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; } #show-more-btn:disabled { background: #ccc; cursor: not-allowed; } </style> </head> <body> <div class="videos-container"> <% videos.forEach(video => { %> <div class="video-card"> <img src="<%= video.image %>" alt="Video thumbnail"> <p>By <%= video.user.name %></p> </div> <% }) %> </div> <button id="show-more-btn" <%= Math.ceil(totalResults /8) <=1 ? 'disabled' : '' %>> <%= Math.ceil(totalResults /8) <=1 ? 'No more videos' : 'Show More' %> </button> <script> let currentPage = 1; const totalResults = <%= totalResults %>; const perPage = 8; const maxPages = Math.ceil(totalResults / perPage); const showMoreBtn = document.getElementById('show-more-btn'); const videosContainer = document.querySelector('.videos-container'); showMoreBtn.addEventListener('click', async () => { currentPage++; showMoreBtn.disabled = true; showMoreBtn.textContent = 'Loading...'; try { const response = await fetch(`/api/videos?page=${currentPage}`); if (!response.ok) throw new Error('Request failed'); const { videos } = await response.json(); // Append new videos to the container videos.forEach(video => { const card = document.createElement('div'); card.className = 'video-card'; card.innerHTML = ` <img src="${video.image}" alt="Video thumbnail"> <p>By ${video.user.name}</p> `; videosContainer.appendChild(card); }); // Disable button if we've reached the last page if (currentPage >= maxPages) { showMoreBtn.textContent = 'No more videos'; showMoreBtn.disabled = true; } else { showMoreBtn.textContent = 'Show More'; showMoreBtn.disabled = false; } } catch (err) { console.error('Error loading videos:', err); showMoreBtn.textContent = 'Show More'; showMoreBtn.disabled = false; alert('Failed to load more videos. Please try again later.'); } }); </script> </body> </html>
3. Key Notes & Improvements
- UX Enhancements: The button shows a loading state while fetching, and disables automatically when all pages are loaded.
- Error Handling: We catch errors on both backend and frontend, providing clear feedback to users.
- Consistent Styling: Dynamically added video cards match the initial ones to keep your UI uniform.
- Security: Sensitive API keys are stored in environment variables instead of being hardcoded.
内容的提问来源于stack exchange,提问作者r121
相关产品推荐
相关产品推荐

