initial commit

This commit is contained in:
2026-01-29 20:06:03 +08:00
commit 21cae2336c
14 changed files with 1530 additions and 0 deletions

343
js/script.js Normal file
View File

@@ -0,0 +1,343 @@
// 全局变量
let videos = [];
let currentCategory = '全部';
// DOM 元素
const searchInput = document.querySelector('.search-input');
const searchBtn = document.querySelector('.search-btn');
const searchResults = document.querySelector('.search-results');
const searchResultsContent = document.querySelector('.search-results-content');
const videoGrid = document.querySelector('.video-grid');
const shortsGrid = document.querySelector('.shorts-grid');
const categoryBtns = document.querySelectorAll('.category-btn');
const subscriptionsList = document.querySelector('.subscriptions-list');
// 初始化
async function init() {
// 加载视频数据
await loadVideos();
// 渲染视频
renderVideos();
// 渲染 Shorts
renderShorts();
// 渲染订阅内容
renderSubscriptions();
// 绑定事件
bindEvents();
}
// 加载视频数据
async function loadVideos() {
try {
const response = await fetch('src/media.json');
videos = await response.json();
} catch (error) {
console.error('加载视频数据失败:', error);
// 使用默认数据
videos = [];
}
}
// 渲染视频
function renderVideos() {
const filteredVideos = filterVideosByCategory(currentCategory);
videoGrid.innerHTML = '';
filteredVideos.forEach(video => {
if (video.type === 'video') {
const videoCard = createVideoCard(video);
videoGrid.appendChild(videoCard);
}
});
}
// 渲染 Shorts
function renderShorts() {
const filteredVideos = filterVideosByCategory(currentCategory);
shortsGrid.innerHTML = '';
filteredVideos.forEach(video => {
if (video.type === 'short') {
const shortsCard = createShortsCard(video);
shortsGrid.appendChild(shortsCard);
}
});
}
// 根据分类过滤视频
function filterVideosByCategory(category) {
if (category === '全部') {
return videos;
}
// 简单的分类映射
const categoryMap = {
'音乐': ['音乐'],
'游戏': ['游戏'],
'直播': ['直播'],
'合辑': ['合辑'],
'动画': ['动画'],
'手工艺品': ['手工艺品'],
'最近上传': videos.filter(v => v.uploadDate.includes('天前')),
'已观看': [],
'发现新视频': videos
};
if (categoryMap[category]) {
if (Array.isArray(categoryMap[category]) && categoryMap[category].length > 0 && typeof categoryMap[category][0] === 'string') {
return videos.filter(v => categoryMap[category].includes(v.category));
} else if (Array.isArray(categoryMap[category])) {
return categoryMap[category];
}
}
return videos;
}
// 创建视频卡片
function createVideoCard(video) {
const card = document.createElement('div');
card.className = 'video-card';
card.innerHTML = `
<div class="video-thumbnail">
<img src="${video.thumbnail}" alt="${video.title}">
<span class="video-duration">${video.duration}</span>
</div>
<div class="video-info">
<div class="video-channel-avatar">
<i class="fas fa-user"></i>
</div>
<div class="video-details">
<h3 class="video-title">${video.title}</h3>
<div class="video-meta">
<div class="video-channel">${video.channel}</div>
<div class="video-stats">
<span>${video.views} 次观看</span>
<span>${video.uploadDate}</span>
</div>
</div>
</div>
<div class="video-menu">
<button class="menu-toggle">
<i class="fas fa-ellipsis-v"></i>
</button>
<div class="menu-dropdown">
<div class="menu-item">
<i class="fas fa-plus"></i>
<span>添加到待播列表</span>
</div>
<div class="menu-item">
<i class="fas fa-clock"></i>
<span>保存到"稍后再看"</span>
</div>
<div class="menu-item">
<i class="fas fa-list"></i>
<span>保存到播放列表</span>
</div>
<div class="menu-item">
<i class="fas fa-download"></i>
<span>下载</span>
</div>
<div class="menu-item">
<i class="fas fa-share"></i>
<span>分享</span>
</div>
<div class="menu-item">
<i class="fas fa-thumbs-down"></i>
<span>不感兴趣</span>
</div>
<div class="menu-item">
<i class="fas fa-ban"></i>
<span>不推荐此频道</span>
</div>
<div class="menu-item">
<i class="fas fa-flag"></i>
<span>举报</span>
</div>
</div>
</div>
</div>
`;
// 绑定菜单事件
const menuToggle = card.querySelector('.menu-toggle');
const menuDropdown = card.querySelector('.menu-dropdown');
menuToggle.addEventListener('click', (e) => {
e.stopPropagation();
menuDropdown.classList.toggle('show');
});
// 点击其他地方关闭菜单
document.addEventListener('click', () => {
menuDropdown.classList.remove('show');
});
return card;
}
// 创建 Shorts 卡片
function createShortsCard(video) {
const card = document.createElement('div');
card.className = 'shorts-card';
card.innerHTML = `
<div class="shorts-thumbnail">
<img src="${video.thumbnail}" alt="${video.title}">
</div>
<div class="shorts-info">
<h3 class="shorts-title">${video.title}</h3>
<div class="shorts-stats">
<span><i class="fas fa-eye"></i>${video.views}</span>
<span><i class="fas fa-clock"></i>${video.uploadDate}</span>
</div>
</div>
`;
return card;
}
// 渲染订阅内容
function renderSubscriptions() {
const subscriptions = [
{ name: '编程大师', avatar: 'https://picsum.photos/id/100/48/48' },
{ name: '前端开发', avatar: 'https://picsum.photos/id/101/48/48' },
{ name: '数据科学', avatar: 'https://picsum.photos/id/102/48/48' },
{ name: 'AI 研究', avatar: 'https://picsum.photos/id/103/48/48' },
{ name: '设计达人', avatar: 'https://picsum.photos/id/104/48/48' }
];
subscriptionsList.innerHTML = '';
subscriptions.forEach(sub => {
const item = document.createElement('div');
item.className = 'subscription-item';
item.innerHTML = `
<div class="subscription-avatar">
<img src="${sub.avatar}" alt="${sub.name}">
</div>
<div class="subscription-name">${sub.name}</div>
`;
subscriptionsList.appendChild(item);
});
}
// 执行搜索
function performSearch(query) {
if (!query.trim()) {
searchResults.style.display = 'none';
return;
}
const results = videos.filter(video =>
video.title.toLowerCase().includes(query.toLowerCase()) ||
video.channel.toLowerCase().includes(query.toLowerCase())
);
renderSearchResults(results, query);
}
// 渲染搜索结果
function renderSearchResults(results, query) {
searchResultsContent.innerHTML = '';
if (results.length === 0) {
searchResultsContent.innerHTML = '<p>没有找到相关视频</p>';
searchResults.style.display = 'block';
return;
}
results.forEach(video => {
const item = document.createElement('div');
item.className = 'search-result-item';
// 高亮关键词
const highlightedTitle = video.title.replace(new RegExp(`(${query})`, 'gi'), '<span class="highlight">$1</span>');
const highlightedChannel = video.channel.replace(new RegExp(`(${query})`, 'gi'), '<span class="highlight">$1</span>');
item.innerHTML = `
<div class="search-result-thumbnail">
<img src="${video.thumbnail}" alt="${video.title}">
</div>
<div class="search-result-details">
<h4 class="search-result-title">${highlightedTitle}</h4>
<div class="search-result-channel">${highlightedChannel}</div>
<div class="search-result-stats">${video.views} 次观看 · ${video.uploadDate}</div>
</div>
`;
searchResultsContent.appendChild(item);
});
searchResults.style.display = 'block';
}
// 绑定事件
function bindEvents() {
// 搜索事件
searchInput.addEventListener('input', (e) => {
performSearch(e.target.value);
});
searchBtn.addEventListener('click', () => {
performSearch(searchInput.value);
});
// 点击其他地方关闭搜索结果
document.addEventListener('click', (e) => {
if (!e.target.closest('.search-container') && !e.target.closest('.search-results')) {
searchResults.style.display = 'none';
}
});
// 分类按钮事件
categoryBtns.forEach(btn => {
btn.addEventListener('click', () => {
// 移除所有活动状态
categoryBtns.forEach(b => b.classList.remove('active'));
// 添加当前活动状态
btn.classList.add('active');
// 更新当前分类
currentCategory = btn.textContent;
// 重新渲染视频
renderVideos();
renderShorts();
});
});
// 侧边栏导航按钮事件
const navBtns = document.querySelectorAll('.nav-btn');
navBtns.forEach(btn => {
btn.addEventListener('click', () => {
navBtns.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
});
});
// 订阅板块展开/收起
const subscriptionTitle = document.querySelector('.nav-section-title');
subscriptionTitle.addEventListener('click', () => {
const subscriptionsList = document.querySelector('.subscriptions-list');
const chevron = subscriptionTitle.querySelector('i');
if (subscriptionsList.style.display === 'none') {
subscriptionsList.style.display = 'block';
chevron.style.transform = 'rotate(0deg)';
} else {
subscriptionsList.style.display = 'none';
chevron.style.transform = 'rotate(-90deg)';
}
});
}
// 页面加载完成后初始化
window.addEventListener('DOMContentLoaded', init);