initial commit
This commit is contained in:
343
js/script.js
Normal file
343
js/script.js
Normal 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);
|
||||
Reference in New Issue
Block a user