前端实战:用纯HTML/CSS/JS构建一个多模型AI对比看板
前言
你有没有遇到过这种情况:面对市场上几十个大模型,每个都有不同的能力侧重,想对比又不知道从哪下手?每次查文档、翻评测、开十几个浏览器标签页,效率极低。
本文带你从零搭建一个多模型AI对比看板,纯前端实现,不依赖任何框架,支持模型搜索、标签筛选、卡片对比视图。完整代码约400行,读完就能跑。
为什么需要对比看板 先看一组实际数据。截至2026年6月,Artificial Analysis Intelligence Index追踪的大模型数量已超过50个——Claude、GPT、Gemini、DeepSeek、Qwen、GLM、MiniMax、Kimi……每个模型的上下文窗口、最大输出Token、推理能力、多模态支持、API价格都不同。
对比维度 模型A 模型B 差异
上下文窗口 200K 32K 6.25倍
最大输出 8192 4096 2倍
支持推理 是 否 —
多模态 文本+图片 仅文本 —
这些差异在实际开发中影响巨大:选错模型,要么功能不满足,要么成本远超预算。所以,一个直观的对比工具是刚需。
架构设计 整个看板分为三层:
┌─────────────────────────────┐ │ 搜索 + 筛选栏 │ ← 交互层 ├─────────────────────────────┤ │ 模型卡片网格(Grid布局) │ ← 展示层 │ ┌─────┐ ┌─────┐ ┌─────┐ │ │ │卡片1│ │卡片2│ │卡片3│ │ │ └─────┘ └─────┘ └─────┘ │ ├─────────────────────────────┤ │ 模型数据(静态JSON) │ ← 数据层 └─────────────────────────────┘ 核心设计原则:
纯静态:所有模型数据以JSON形式内嵌,无需后端 响应式:Grid自适应列数,手机也能看 零依赖:不引入任何第三方库 第一步:定义数据结构 每个模型用一个对象表示。字段设计要覆盖实际选型中最关心的维度:
javascript const models = [ { id: "claude-opus-4.8", name: "Claude Opus 4.8", provider: "Anthropic", tags: ["代码", "Agent", "推理"], contextWindow: 200000, maxTokens: 32768, reasoning: true, multimodal: ["text", "image"], strengths: ["Agent任务自动化", "长文本理解", "代码重构"], released: "2026-05", country: "美国" }, { id: "gpt-5.5", name: "GPT-5.5", provider: "OpenAI", tags: ["编程", "知识问答", "创意写作"], contextWindow: 128000, maxTokens: 16384, reasoning: false, multimodal: ["text", "image"], strengths: ["代码生成", "数据分析", "通用对话"], released: "2026-03", country: "美国" }, { id: "gemini-3.1-pro", name: "Gemini 3.1 Pro", provider: "Google", tags: ["多模态", "长上下文", "性价比"], contextWindow: 2000000, maxTokens: 65536, reasoning: true, multimodal: ["text", "image", "audio", "video"], strengths: ["多模态理解", "超长上下文检索", "视频分析"], released: "2026-04", country: "美国" }, { id: "deepseek-v4-pro", name: "DeepSeek V4-Pro", provider: "DeepSeek", tags: ["推理", "长上下文", "高性价比"], contextWindow: 131072, maxTokens: 32768, reasoning: true, multimodal: ["text"], strengths: ["百万Token检索", "知识推理", "批量处理"], released: "2026-05", country: "中国" }, { id: "qwen3.6-plus", name: "Qwen3.6 Plus", provider: "阿里云", tags: ["编程", "中文", "多语言"], contextWindow: 256000, maxTokens: 16384, reasoning: true, multimodal: ["text", "image"], strengths: ["中文编程", "多语言翻译", "文档问答"], released: "2026-06", country: "中国" }, { id: "glm-5.2", name: "GLM-5.2", provider: "智谱AI", tags: ["中文理解", "网页设计", "Agent"], contextWindow: 128000, maxTokens: 8192, reasoning: true, multimodal: ["text", "image"], strengths: ["中文多轮对话", "UI设计生成", "知识密度"], released: "2026-06", country: "中国" }, { id: "minimax-m3", name: "MiniMax M3", provider: "MiniMax", tags: ["超长上下文", "多模态", "批量文案"], contextWindow: 1000000, maxTokens: 16384, reasoning: false, multimodal: ["text", "image", "audio"], strengths: ["百万级上下文", "长文生成", "语音合成"], released: "2026-05", country: "中国" }, { id: "kimi-k2.6", name: "Kimi K2.6", provider: "月之暗面", tags: ["代码", "推理", "开源"], contextWindow: 131072, maxTokens: 16384, reasoning: true, multimodal: ["text"], strengths: ["代码专项", "开源部署", "Agent编排"], released: "2026-05", country: "中国" } ]; 数据结构设计要点:
tags 是筛选的核心维度,要用产品经理思维设计——用户看到标签就知道模型定位 strengths 用自然语言描述,既作为卡片展示内容,也可用于模糊搜索 contextWindow 和 maxTokens 是硬指标,必须准确 第二步:构建筛选系统 筛选是看板的核心交互。我们需要实现两种筛选:标签多选和关键词搜索。
2.1 生成标签按钮 javascript function initFilters() { // 收集所有不重复标签 const allTags = [...new Set(models.flatMap(m => m.tags))]; const filterBar = document.getElementById('filterTags');
allTags.forEach(tag => { const btn = document.createElement('button'); btn.className = 'tag-btn'; btn.textContent = tag; btn.onclick = () => { btn.classList.toggle('active'); renderCards(); }; filterBar.appendChild(btn); }); } 2.2 组合筛选逻辑 javascript function getFilteredModels() { const keyword = document.getElementById('searchInput').value.toLowerCase(); const activeTags = [...document.querySelectorAll('.tag-btn.active')] .map(btn => btn.textContent);
return models.filter(model => { // 关键词筛选:匹配名称、提供商、优势描述 const matchKeyword = !keyword || model.name.toLowerCase().includes(keyword) || model.provider.toLowerCase().includes(keyword) || model.tags.some(t => t.toLowerCase().includes(keyword)) || model.strengths.some(s => s.toLowerCase().includes(keyword));
// 标签筛选:AND逻辑(选中多个标签时,模型必须全包含)
const matchTags = activeTags.length === 0 ||
activeTags.every(tag => model.tags.includes(tag));
return matchKeyword && matchTags;
}); } 这里有一个关键决策:标签筛选用 AND 还是 OR?
AND:用户选"代码"+"推理",只显示同时具备这两个标签的模型(精确匹配) OR:用户选"代码"+"推理",显示具备任意一个标签的模型(宽松匹配) 我选择了 AND。因为在实际选型场景中,用户通常有明确的组合需求。比如"我需要一个既支持多模态又有推理能力的模型",AND 能直接给出结果;OR 会把范围放大,反而增加筛选难度。
第三步:渲染卡片 卡片的视觉设计直接影响信息传达效率。我的设计原则是:
头部:模型名称 + 提供商,一目了然 标签区:色彩编码,快速识别定位 指标区:上下文窗口、最大输出等硬指标用图标+数字展示 优势区:自然语言描述核心竞争力 javascript function renderCards() { const grid = document.getElementById('modelGrid'); const filtered = getFilteredModels();
grid.innerHTML = filtered.map(model => <div class="model-card"> <div class="card-header"> <h3>${model.name}</h3> <span class="provider">${model.provider}</span> </div> <div class="card-tags"> ${model.tags.map(t =>{t}</span>`).join('')} </div> <div class="card-metrics"> <div class="metric"> <span class="metric-icon">📐</span> <span class="metric-label">上下文</span> <span class="metric-value">{formatTokens(model.contextWindow)}
<li>${s}</li>).join('')} // 显示筛选结果数量
document.getElementById('resultCount').textContent =
共 ${filtered.length} 个模型;
}
function formatTokens(n) { if (n >= 1000000) return (n / 1000000).toFixed(1) + 'M'; if (n >= 1000) return (n / 1000).toFixed(0) + 'K'; return n.toString(); } 第四步:CSS Grid响应式布局 Grid是现代CSS布局的最佳选择,天然支持响应式。我用 auto-fill + minmax() 实现列数自适应:
css .model-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 20px; padding: 20px 0; }
.model-card { background: #ffffff; border: 1px solid #e8ecf1; border-radius: 12px; padding: 24px; transition: transform 0.2s, box-shadow 0.2s; }
.model-card:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(0,0,0,0.08); }
.card-header { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 12px; padding-bottom: 12px; border-bottom: 1px solid #f0f2f5; }
.card-header h3 { font-size: 18px; font-weight: 600; color: #1a1a2e; margin: 0; }
.provider { font-size: 13px; color: #8896a7; }
.card-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 16px; }
.tag { padding: 3px 10px; border-radius: 20px; font-size: 12px; font-weight: 500; }
.tag.代码 { background: #e3f2fd; color: #1565c0; } .tag.推理 { background: #f3e5f5; color: #7b1fa2; } .tag.Agent { background: #e8f5e9; color: #2e7d32; } .tag.多模态 { background: #fff3e0; color: #e65100; } .tag.中文 { background: #fce4ec; color: #c62828; } .tag.长上下文 { background: #e0f7fa; color: #00695c; } .tag.编程 { background: #ede7f6; color: #4527a0; } .tag.高性价比 { background: #e8eaf6; color: #283593; } .tag.中文理解 { background: #fff8e1; color: #f57f17; } .tag.开源 { background: #f1f8e9; color: #33691e; } .tag.网页设计 { background: #fbe9e7; color: #bf360c; } .tag.超长上下文 { background: #e0f2f1; color: #004d40; } .tag.批量文案 { background: #fce4ec; color: #880e4f; } .tag.多语言 { background: #e1f5fe; color: #01579b; } .tag.知识问答 { background: #f3e5f5; color: #4a148c; } .tag.创意写作 { background: #fff9c4; color: #f57f17; } .tag.性价比 { background: #e8eaf6; color: #1a237e; }
.card-metrics { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 16px; padding: 12px; background: #f8f9fb; border-radius: 8px; }
.metric { display: flex; flex-direction: column; gap: 2px; }
.metric-label { font-size: 11px; color: #8896a7; text-transform: uppercase; }
.metric-value { font-size: 14px; font-weight: 600; color: #1a1a2e; }
.card-strengths h4 { font-size: 13px; color: #8896a7; margin: 0 0 8px 0; }
.card-strengths ul { list-style: none; padding: 0; margin: 0; }
.card-strengths li { padding: 4px 0; font-size: 13px; color: #4a5568; position: relative; padding-left: 16px; }
.card-strengths li::before { content: "▸"; position: absolute; left: 0; color: #4a90d9; }
/* 搜索栏 */ .search-bar { display: flex; gap: 12px; margin-bottom: 16px; }
.search-input { flex: 1; padding: 10px 16px; border: 1px solid #dde1e7; border-radius: 8px; font-size: 14px; outline: none; transition: border-color 0.2s; }
.search-input:focus { border-color: #4a90d9; }
/* 筛选标签栏 */ .filter-bar { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 20px; }
.tag-btn { padding: 6px 16px; border: 1px solid #dde1e7; border-radius: 20px; background: #fff; font-size: 13px; color: #4a5568; cursor: pointer; transition: all 0.2s; }
.tag-btn:hover { border-color: #4a90d9; color: #4a90d9; }
.tag-btn.active { background: #4a90d9; border-color: #4a90d9; color: #fff; }
/* 结果计数 */ .result-info { font-size: 13px; color: #8896a7; margin-bottom: 12px; }
/* 响应式 */ @media (max-width: 768px) { .model-grid { grid-template-columns: 1fr; gap: 16px; }
.card-metrics { grid-template-columns: 1fr 1fr; } } 第五步:HTML骨架 html
多模型AI对比看板AI模型对比看板
支持标签筛选与关键词搜索,快速找到适合场景的模型
<div class="search-bar">
<input
type="text"
id="searchInput"
class="search-input"
placeholder="搜索模型名称、提供商、优势..."
oninput="renderCards()"
>
</div>
<div class="filter-bar" id="filterTags"></div>
<div class="result-info" id="resultCount"></div>
<div class="model-grid" id="modelGrid"></div>
javascript // 全局状态 let compareList = []; const MAX_COMPARE = 3;
function toggleCompare(modelId) {
const card = document.querySelector([data-id="${modelId}"]);
if (compareList.includes(modelId)) { compareList = compareList.filter(id => id !== modelId); card.classList.remove('selected'); } else if (compareList.length < MAX_COMPARE) { compareList.push(modelId); card.classList.add('selected'); }
updateComparePanel(); }
function updateComparePanel() { const panel = document.getElementById('comparePanel'); if (compareList.length === 0) { panel.style.display = 'none'; return; }
panel.style.display = 'block'; const selected = models.filter(m => compareList.includes(m.id));
// 生成对比表格
panel.innerHTML = <h3>模型对比 (${compareList.length}/${MAX_COMPARE})</h3> <table> <thead> <tr> <th>维度</th> ${selected.map(m =>{m.name}</th>`).join('')} </tr> </thead> <tbody> <tr> <td>上下文窗口</td>
{selected.map(m => <td>${formatTokens(m.contextWindow)}</td>).join('')} 最大输出
{selected.map(m => `<td>{formatTokens(m.maxTokens)}).join('')} </tr> <tr> <td>推理能力</td> ${selected.map(m => {m.reasoning ? '✓' : '✗'}</td>`).join('')} </tr> <tr> <td>多模态</td>
{selected.map(m => <td>${m.multimodal.join('、')}</td>).join('')}
`;
}
在卡片模板中加入对比按钮和 data-id 属性:
javascript // 在卡片HTML中加入 data-id="{model.id}')"> ${compareList.includes(model.id) ? '取消对比' : '加入对比'} 技术要点总结 技术决策 选择 原因 数据存储 静态JSON 数据量小,无需后端,部署简单 布局方案 CSS Grid 响应式天然支持,代码量少 标签筛选 AND逻辑 精确匹配更符合选型场景 搜索策略 模糊多字段 名称+标签+优势同时匹配 对比上限 3个 保持信息密度可控 依赖策略 零依赖 减小加载体积,避免版本冲突 写在最后 这个对比看板的核心价值在于:把零散的模型信息结构化为可筛选、可对比的视图。实际使用时,你可以根据自己的需求扩展数据字段(比如加上价格、API调用方式、支持的语言等)。
完整代码约400行,纯前端即可运行,拖到浏览器里就能用。如果需要对接到实时数据,只需要把静态JSON替换成API调用,其余逻辑不变。
本文为纯技术分享,不涉及任何商业推广。文中数据来源于公开Benchmark评测与各厂商官方文档,仅供参考。