【零代码AI编程实战】系列
3、 【零代码AI编程实战】热搜从0到1技术方案(本篇)
前言:信息爆炸时代,如何快速获取全网热点资讯?本文将深入解析AI灯塔导航系统中热搜卡片功能的完整实现方案,从后端数据抓取到前端界面展示,带你领略一个功能完整的实时热搜系统的技术魅力。
🎯 一、热搜成果展示(文末有惊喜)
在AI灯塔导航系统中,热搜卡片是一个核心功能模块,旨在为用户提供一站式的热点资讯聚合服务。不同于传统的单一平台热搜,我们的系统整合了56个主流平台的热搜数据,包括:
- 社交媒体:微博、知乎、B站、抖音、快手等
- 搜索引擎:百度热搜榜
- 技术社区:GitHub、CSDN、掘金、V2EX等
- 新闻资讯:今日头条、澎湃新闻、腾讯新闻等
- 游戏娱乐:原神、崩坏3、英雄联盟等


这种多平台聚合的设计理念,让用户无需在多个平台间切换,就能快速掌握全网热点动态,目前卡片暂时开放了7个平台数据。
🏗️ 二、热搜整体架构图
功能架构图

数据流时序图
🏗️ 三、热搜接口实现
后端服务架构
1小时TTL] --> W[快速响应] X[数据库缓存
持久化] --> Y[数据可靠性] end A --> G C --> G E --> G G --> K K --> P K --> R K --> V K --> X style G fill:#f8cecc style K fill:#fff2cc style P fill:#d5e8d4 style V fill:#e1d5e7
1、数据抓取策略
数据抓取采用了模块化设计,每个平台都有独立的抓取逻辑:
javascript
// 平台抓取器映射
const platformGetters = {
weibo: getWeiboHotSearch, // 微博热搜
baidu: getBaiduHotSearch, // 百度热搜
bilibili: getBilibiliHotSearch, // B站热门
zhihu: getZhihuHotSearch, // 知乎热榜
douyin: getDouyinHotSearch, // 抖音热点
// ... 更多平台
};
javascript
/**
* 今日头条抓取逻辑
*/
const axios = require('axios');
/**
* 获取今日头条数据
*/
const getToutiaoHotSearch = async () => {
try {
console.log('今日头条: 开始获取数据...');
const url = 'https://www.toutiao.com/hot-event/hot-board/?origin=toutiao_pc';
console.log('今日头条: 发送API请求...');
const response = await axios.get(url, {
timeout: 15000,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Referer': 'https://www.toutiao.com/',
'Cache-Control': 'no-cache',
'Pragma': 'no-cache'
}
});
console.log('今日头条: API请求成功');
const list = response.data.data;
if (!list || !Array.isArray(list) || list.length === 0) {
throw new Error('无法获取今日头条数据');
}
console.log(`今日头条: 获取到 ${list.length} 条数据`);
const data = list.map((v) => ({
id: v.ClusterIdStr,
title: v.Title,
cover: v.Image.url,
timestamp: undefined,
hot: Number(v.HotValue),
url: `https://www.toutiao.com/trending/${v.ClusterIdStr}/`,
mobileUrl: `https://api.toutiaoapi.com/feoffline/amos_land/new/html/main/index.html?topic_id=${v.ClusterIdStr}`,
}));
console.log('今日头条: 数据处理完成');
return {
platform: 'toutiao',
name: 'toutiao',
title: '今日头条',
type: '热榜',
link: 'https://www.toutiao.com/',
total: data.length,
data: data
};
} catch (error) {
console.log('今日头条: 发生错误:', error.message);
console.log('今日头条: 错误堆栈:', error.stack);
throw new Error(`获取今日头条失败: ${error.message}`);
}
};
module.exports = {
getToutiaoHotSearch
};
2、缓存机制设计
为了提升用户体验和减少服务器压力,我们实现了双层缓存策略:
- 内存缓存:1小时TTL,快速响应
- 数据库缓存:MongoDB持久化存储,数据可靠性
javascript
const CACHE_TTL = 60 * 60 * 1000; // 1小时缓存
const isCacheValid = (updateTime) => {
if (!updateTime) return false;
const now = new Date();
const update = new Date(updateTime);
return (now - update) < CACHE_TTL;
};
🔌 3、接口实现详解
RESTful API设计
我们设计了完整的RESTful API体系,支持多种数据获取方式:
1. 获取所有平台热搜数据
http
GET /api/hot-search
2. 获取指定平台热搜数据
http
GET /api/hot-search/:platform?refresh=true
3. 获取支持的平台列表
http
GET /api/hot-search/platforms
数据模型设计
javascript
// 热搜条目模式
const hotSearchItemSchema = new mongoose.Schema({
id: { type: String, required: true },
title: { type: String, required: true, trim: true },
desc: { type: String, default: '' },
url: { type: String, required: true },
mobileUrl: { type: String, default: '' },
timestamp: { type: String, default: '' },
hot: { type: String, default: '' },
author: { type: String, default: '' }
});
// 热搜数据模式
const hotSearchSchema = new mongoose.Schema({
platform: { type: String, required: true, trim: true },
name: { type: String, required: true, trim: true },
title: { type: String, required: true, trim: true },
type: { type: String, required: true, trim: true },
description: { type: String, default: '' },
link: { type: String, default: '' },
total: { type: Number, default: 0 },
data: [hotSearchItemSchema],
updateTime: { type: Date, default: Date.now },
fromCache: { type: Boolean, default: false }
});
错误处理与容错机制
javascript
exports.getHotSearchByPlatform = async (req, res) => {
try {
const { platform } = req.params;
const { refresh } = req.query;
const forceRefresh = refresh === 'true';
const data = await hotSearchService.getHotSearchByPlatform(platform, forceRefresh);
res.status(200).json({
success: true,
code: 200,
...data
});
} catch (error) {
logger.error(`获取热搜数据失败: ${error.message}`);
res.status(500).json({
success: false,
code: 500,
error: '获取热搜数据失败',
message: error.message
});
}
};
🎨 四、界面实现与交互
前端组件详细架构
主组件] --> B[CommonCard.js
通用卡片] B --> C[HotSearchContent.js
内容组件] C --> D[平台标签栏] C --> E[热搜列表] C --> F[加载状态] C --> G[错误处理] end subgraph "状态管理" H[hotSearchSlice.js] --> I[平台数据] H --> J[加载状态] H --> K[错误信息] H --> L[活跃平台] end subgraph "服务层" M[hotSearchService.js] --> N[API调用] M --> O[数据处理] M --> P[错误处理] end subgraph "样式系统" Q[HotSearchContent.css] --> R[深色主题] Q --> S[高斯模糊] Q --> T[响应式布局] Q --> U[动画效果] end A --> H C --> M C --> Q style A fill:#e1d5e7 style H fill:#fff2cc style M fill:#f8cecc style Q fill:#d5e8d4
1、组件架构设计
热搜卡片采用了分层组件设计,确保代码的可维护性和复用性:
javascript
// 主组件:HotSearch.js
const HotSearch = ({ onSave }) => {
const handleAdd = () => {
const websiteData = {
name: '热搜',
iconColor: '#ffffff',
textIcon: '热搜',
url: 'https://www.aidengta.cn',
dataType: DATA_TYPE.HOT_SEARCH,
id: `hotsearch_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`,
preferredIconType: PREFERRED_ICON_TYPE.TEXT,
category: '热搜卡片',
description: '聚合百度,B站,微博,知乎,头条等热搜!'
};
if (onSave) {
onSave(websiteData);
}
};
return (
<CommonCard
title="热搜"
subtitle="聚合百度,B站,微博,知乎,头条,抖音,掘金等热搜!"
onAdd={handleAdd}
addButtonText="添加"
scrollDirection="vertical"
>
<HotSearchContent />
</CommonCard>
);
};
2、状态管理实现
使用Redux进行状态管理,确保数据流的清晰和可预测:
javascript
// Redux Slice
const hotSearchSlice = createSlice({
name: 'hotSearch',
initialState: {
platforms: {},
supportedPlatforms: [],
loading: {},
errors: {}
},
reducers: {
setActivePlatform: (state, action) => {
state.activePlatform = action.payload;
},
setPlatformData: (state, action) => {
const { platform, data } = action.payload;
state.platforms[platform] = data;
}
}
});
3、交互体验优化
1. 平台切换交互
javascript
const handlePlatformChange = (e, platform) => {
e.stopPropagation();
// 如果是重复点击同一个平台,强制刷新数据
if (activePlatform === platform) {
dispatch(fetchHotSearchByPlatform({ platform, refresh: true }));
} else {
// 切换到新平台
setActivePlatformLocal(platform);
dispatch(setActivePlatform(platform));
// 如果该平台数据不存在,则获取数据
if (!platformData) {
dispatch(fetchHotSearchByPlatform({ platform }));
}
}
};
2. 热搜项目点击处理
javascript
const handleTopicClick = (e, topic) => {
e.stopPropagation();
let url = topic.url || topic.link || topic.href;
// 如果没有直接链接,尝试构建链接
if (!url && topic.title) {
const searchUrl = getSearchUrl(activePlatform, topic.title);
if (searchUrl) {
url = searchUrl;
}
}
if (url) {
window.open(url, '_blank', 'noopener,noreferrer');
}
};
4、视觉设计特色
热搜卡片采用了深色主题设计,配合高斯模糊效果,营造出现代感十足的视觉体验:
css
/* 热搜内容区域容器 - 深灰色渐变背景 + 高斯模糊 */
.hot-search-content__area {
background: linear-gradient(135deg, rgba(9, 9, 9, 0.9) 0%, rgba(44, 62, 80, 0.8) 50%, rgba(52, 73, 94, 0.7) 100%);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-radius: 8px;
padding: 8px;
}
/* 平台标签按钮 - 紧凑设计 + 高斯模糊 */
.hot-search-content__tab {
background: rgba(52, 73, 94, 0.6);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: none;
padding: 2px 10px;
border-radius: 11px;
font-size: 12px;
color: #bdc3c7;
cursor: pointer;
transition: all 0.2s ease;
}

📱 5、Grid布局与响应式设计
Grid布局实现
使用了支持拖动排序和栅栏比例的开源库react-grid-layout,热搜卡片支持在网格布局中多列多行占用,通过CSS Grid实现灵活的布局控制:
css
// 根据应用数据动态生成布局 - 支持智能碰撞检测和自动换行
const generateLayout = (appsData) => {
const layout = [];
const cols = gridCols; // 使用动态列数
// 使用二维数组来跟踪已占用的网格位置
const grid = Array(20).fill(null).map(() => Array(cols).fill(false));
appsData.forEach((app) => {
// 根据 dataType 确定网格占用大小
let itemWidth = 1;
let itemHeight = 1;
if (app.dataType === DATA_TYPE.HOT_SEARCH) {
// 详情模式占用3列,其他模式占用4列
itemWidth = websiteDisplayMode === 'detailed' ? 2 : 4;
itemHeight = 2; // 占用2行
}
// 找到第一个可用的位置
let found = false;
let itemX = 0;
let itemY = 0;
for (let y = 0; y < grid.length && !found; y++) {
for (let x = 0; x <= cols - itemWidth && !found; x++) {
// 检查这个位置是否有足够的空间
let canPlace = true;
for (let dy = 0; dy < itemHeight && canPlace; dy++) {
for (let dx = 0; dx < itemWidth && canPlace; dx++) {
if (y + dy >= grid.length || x + dx >= cols || grid[y + dy][x + dx]) {
canPlace = false;
}
}
}
if (canPlace) {
itemX = x;
itemY = y;
found = true;
// 标记这个位置为已占用
for (let dy = 0; dy < itemHeight; dy++) {
for (let dx = 0; dx < itemWidth; dx++) {
if (y + dy < grid.length && x + dx < cols) {
grid[y + dy][x + dx] = true;
}
}
}
}
}
}
if (found) {
layout.push({
i: app.complexId || app.id,
x: itemX,
y: itemY,
w: itemWidth,
h: itemHeight,
static: false
});
} else {
// 如果找不到合适的位置,放在最后一行
logger.warn(`[generateLayout] 无法为 ${app.name} 找到合适位置,放在最后一行`);
layout.push({
i: app.complexId || app.id,
x: 0,
y: Math.max(...layout.map(item => item.y + item.h), 0),
w: itemWidth,
h: itemHeight,
static: false
});
}
});
// 添加按钮跟随在最后一个item后面,除非一行已满才到下一行
if (layout.length > 0) {
// 找到最后一个item的位置和尺寸
const lastItem = layout[layout.length - 1];
const lastItemEndX = lastItem.x + lastItem.w;
const lastItemY = lastItem.y;
// 检查当前行是否还有空间
if (lastItemEndX + 1 <= cols) {
// 当前行还有空间,放在最后一个item后面
layout.push({
i: 'add-button',
x: lastItemEndX,
y: lastItemY,
w: 1,
h: 1,
static: true // 设置为静态,不参与拖动
});
} else {
// 当前行已满,放到下一行开头
layout.push({
i: 'add-button',
x: 0,
y: lastItemY + lastItem.h,
w: 1,
h: 1,
static: true // 设置为静态,不参与拖动
});
}
} else {
// 如果没有其他item,放在(0,0)位置
layout.push({
i: 'add-button',
x: 0,
y: 0,
w: 1,
h: 1,
static: true // 设置为静态,不参与拖动
});
}
console.log('generateLayout 布局:', layout);
return layout;
};
6、响应式设计策略
1. 断点设计
css
/* 桌面端 */
@media (min-width: 1024px) {
.hot-search-content__tabs {
gap: 4px;
margin-bottom: 8px;
}
.hot-search-content__tab {
padding: 2px 10px;
font-size: 12px;
min-width: 46px;
}
}
/* 平板端 */
@media (max-width: 768px) {
.hot-search-content__area {
padding: 10px;
}
.hot-search-content__tabs {
gap: 3px;
margin-bottom: 10px;
}
.hot-search-content__tab {
padding: 3px 10px;
font-size: 11px;
min-width: 45px;
}
}
/* 移动端 */
@media (max-width: 480px) {
.hot-search-content__item {
gap: 6px;
padding: 5px 0;
}
.hot-search-content__title {
font-size: 11px;
}
.hot-search-content__count {
font-size: 10px;
min-width: 45px;
}
}
2. 滚动优化
css
/* 自定义滚动条样式 */
.hot-search-content__list::-webkit-scrollbar {
width: 4px;
}
.hot-search-content__list::-webkit-scrollbar-track {
background: rgba(52, 73, 94, 0.1);
border-radius: 2px;
}
.hot-search-content__list::-webkit-scrollbar-thumb {
background: rgba(52, 73, 94, 0.6);
border-radius: 2px;
}
.hot-search-content__list::-webkit-scrollbar-thumb:hover {
background: rgba(52, 73, 94, 0.8);
}
7、事件处理优化
为了防止在拖拽布局时误触热搜项目,我们实现了完善的事件处理机制:
javascript
// 阻止事件冒泡到 react-grid-layout
const handleItemClick = (e) => {
e.stopPropagation();
e.preventDefault();
// 处理点击逻辑
};
// 阻止滚动事件冒泡
const handleWheel = (e) => {
e.stopPropagation();
e.preventDefault();
};
🚀 五、技术总结与思考
技术亮点
- 模块化架构:每个平台独立的抓取逻辑,便于维护和扩展
- 双层缓存:内存+数据库缓存,平衡性能与可靠性
- 响应式设计:适配多种设备尺寸,提供一致的用户体验
- 事件处理优化:完善的事件冒泡控制,避免布局冲突
- 视觉设计:深色主题+高斯模糊,现代感十足
性能优化策略
- 数据缓存:1小时TTL,减少重复请求
- 懒加载:按需获取平台数据
- 事件防抖:避免频繁的API调用
- CSS优化:使用transform和opacity实现动画
扩展性考虑
- 新平台接入:只需添加对应的抓取器即可
- 数据格式统一:标准化的数据结构,便于扩展
- 组件复用:CommonCard组件可复用于其他功能模块
🎉 六、结语
AI灯塔导航项目,热搜卡片功能 的实现,展现了现代Web开发中前后端分离 、模块化设计 、响应式布局等核心技术的综合运用,希望大家喜欢这个功能。
AI时代,效率为王。希望这个AI导航网站能帮助到你,pc浏览器访问 www.aidengta.cn/ 即刻体验,无需登录无广告无收费!
最后你敢相信吗?热搜这个功能,我用 AI 编程,只用了一周下班的零散时间(每天半小时左右),全程没亲手敲过一行代码 ------ 从 UI 设计、数据获取,到接口实现、前端落地,每一步都是靠 Cursor 主导完成。更绝的是,就连这篇博客,大部分内容也是 Cursor 帮我写的。下面就贴出当时让它写博客的 prompt:
markdown
你是一个技术博客专家,针对实现热搜卡片功能,帮我写一篇技术博客,
从背景/数据来源/接口实现/界面实现/总结等方面阐述下,
要留有放图片的地方,适当加些架构图,运用安装的draw.io输出,
最后在项目根目录blog文件夹输出一个md文件。
要求:
1. 内容结构:从以下几个维度展开
- 背景介绍
- 数据来源与架构
- 接口实现详解
- 界面实现与交互
- Grid布局与响应式设计
- 技术总结与思考
2. 写作风格:生动有趣、易懂
3. 视觉元素:
- 预留图片位置
- 适当添加架构图
- 使用draw.io工具输出图表
4. 输出位置:在项目根目录下的blog文件夹中生成一个md文件
5. 语言:使用中文
6. 架构图要求:
- 每个模块用一个大虚线边框框住
- 用箭头指向各个模块的调用顺序
- 箭头要移到模块外部,避免遮挡内容
- 使用深色背景+白色文字,确保可读性
- 包含详细的技术栈和性能指标
请复述我的需求,我觉得没问题再执行
更多精彩AI资讯与编程首发,关注公众号"程序员码歌":这里将长期专注分享AI工具与AI编程实战,为开发者与AI爱好者提供帮助,让您每次阅读都有些许收获!