《我用原生 JavaScript 写了一个豆包 AI 对话导航栏插件》
我对于JS的学习还不够深入,我的理想模型是和deep seek一样,只有问题的导航,但是我的这个导航不仅有问题还有对应的答案,刚开始我是有点烦的,这并没有达到我的理想目标,但是我的技术有限,只能到这一步,就将就着用了,用了一段时间发现还挺好的,有时候用户的问题也是比较长的,从问题到答案也是很长的要去滑动鼠标,而我的这个插件可以直接到对应的答案,所以我现在挺喜欢用的。这个class更新的时候也会变,
最近经常使用豆包 AI 聊天,但当对话内容变多之后,查找历史问题会变得比较麻烦。
于是我用原生 JavaScript 写了一个简单的浏览器插件,给豆包页面增加了一个侧边导航栏。
可以快速定位历史对话内容。



目前实现的功能:
- 自动提取对话内容
- 侧边栏导航
- 点击快速定位
- 平滑滚动
- 悬停展开动画
const observer = new MutationObserver(() => this.refresh());
当豆包页面新增对话时,自动刷新导航栏。
conv.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
点击导航项后,自动滚动到对应对话位置。
transition: width 0.25s ease;
实现导航栏悬停展开动画。
这是我的文件夹里面的三个文件
content.js
// content.js
// --- 辅助函数:从对话元素中提取文本 ---
function getQuestionText(conversation) {
// 在这里,你要写上一步在开发者工具里找到的 class 名
const userDiv = conversation.querySelector('.w-full');
return userDiv ? userDiv.innerText.slice(0, 30) : `对话 ${Date.now()}`;
}
// --- 导航栏管理器 ---
class NavigationManager {
constructor() {
this.navContainer = null;
this.conversations = [];
}
// 创建导航栏容器并添加到页面
init() {
if (this.navContainer) return;
this.navContainer = document.createElement('div');
this.navContainer.id = 'doubao-nav-sidebar';
this.navContainer.innerHTML = `<h3>📑 对话导航</h3><div class="nav-list"></div>`;
document.body.appendChild(this.navContainer);
}
// 刷新导航列表,映射到每轮对话
refresh() {
// 1. 获取所有对话条目(换成你实际找到的 class 名 .conversation-item)
const conversationElements = document.querySelectorAll('.v_list_row');
if (conversationElements.length === 0) return;
if (conversationElements.length === this.conversations.length) return;
// 2. 更新存储的对话列表
this.conversations = Array.from(conversationElements);
const navListDiv = this.navContainer?.querySelector('.nav-list');
if (!navListDiv) return;
// 3. 清空并重新生成导航链接
navListDiv.innerHTML = '';
this.conversations.forEach((conv, index) => {
const question = getQuestionText(conv);
const navItem = document.createElement('div');
navItem.className = 'nav-item';
navItem.textContent = `${index + 1}. ${question}`;
// 点击时滚动到对应对话
navItem.onclick = () => {
conv.scrollIntoView({ behavior: 'smooth', block: 'start' });
// 可选:高亮当前激活的导航项
document.querySelectorAll('.nav-item').forEach(item => item.classList.remove('active'));
navItem.classList.add('active');
};
navListDiv.appendChild(navItem);
});
}
// 监听页面变化,自动更新导航
observeConversations() {
const observer = new MutationObserver(() => this.refresh());
const targetNode = document.querySelector('.list_items'); // 换成你实际找到的容器 class 名
if (targetNode) {
observer.observe(targetNode, { childList: true, subtree: true });
}
}
}
// --- 启动扩展---
const nav = new NavigationManager();
nav.init();
setTimeout(() => { nav.refresh(); nav.observeConversations(); }, 1000);
styles.css
/* styles.css - 豆包导航栏:悬停展开,平时隐藏 */
#doubao-nav-sidebar {
position: fixed;
right: 20px;
top: 50%;
transform: translateY(-50%);
width: 40px;
/* 默认很窄 */
max-height: 70vh;
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(12px);
border-radius: 24px;
/* 圆润一点 */
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
padding: 12px 0;
z-index: 10000;
display: flex;
flex-direction: column;
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, sans-serif;
border: 1px solid rgba(0, 0, 0, 0.08);
transition: width 0.25s ease, background 0.2s ease;
/* 平滑过渡 */
overflow: hidden;
/* 溢出内容隐藏,避免变形 */
}
/* 悬停时展开 */
#doubao-nav-sidebar:hover {
width: 240px;
background: rgba(255, 255, 255, 0.98);
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.12);
}
/* 标题默认隐藏,悬停时显示 */
#doubao-nav-sidebar h3 {
font-size: 14px;
font-weight: 600;
margin: 0 16px 12px 16px;
padding-bottom: 8px;
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
color: #1a1a1a;
white-space: nowrap;
opacity: 0;
/* 默认透明 */
transition: opacity 0.2s ease 0.05s;
}
#doubao-nav-sidebar:hover h3 {
opacity: 1;
/* 悬停时出现标题 */
}
/* 导航列表默认隐藏,悬停时显示滚动条 */
#doubao-nav-sidebar .nav-list {
overflow-y: auto;
flex: 1;
padding: 0 8px;
opacity: 0;
transition: opacity 0.2s ease 0.05s;
}
#doubao-nav-sidebar:hover .nav-list {
opacity: 1;
}
/* 导航项目样式保持不变,但为了悬停窄条时显示一个简单提示,可以加个伪元素 */
#doubao-nav-sidebar::before {
content: "📑";
font-size: 20px;
text-align: center;
display: block;
line-height: 1;
transition: opacity 0.2s;
}
/* 悬停时隐藏这个简单的图标(因为标题会显示出来) */
#doubao-nav-sidebar:hover::before {
opacity: 0;
pointer-events: none;
}
/* 调整导航项目的基础样式(确保窄条下不显示文字) */
#doubao-nav-sidebar .nav-item {
padding: 8px 12px;
margin: 4px 0;
border-radius: 12px;
font-size: 13px;
cursor: pointer;
color: #333;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
transition: background 0.15s, color 0.15s;
opacity: 0;
/* 默认不可见 */
transform: translateX(10px);
/* 轻微偏移,增加动画感 */
transition: opacity 0.2s, transform 0.2s;
}
#doubao-nav-sidebar:hover .nav-item {
opacity: 1;
transform: translateX(0);
}
/* 悬停时每个项目依次显现(可选,更优雅) */
#doubao-nav-sidebar:hover .nav-item:nth-child(1) {
transition-delay: 0.02s;
}
#doubao-nav-sidebar:hover .nav-item:nth-child(2) {
transition-delay: 0.04s;
}
#doubao-nav-sidebar:hover .nav-item:nth-child(3) {
transition-delay: 0.06s;
}
/* 你可以继续加到 10 左右,但浏览器会自动处理,没关系 */
/* 自定义滚动条不变 */
#doubao-nav-sidebar .nav-list::-webkit-scrollbar {
width: 4px;
}
#doubao-nav-sidebar .nav-list::-webkit-scrollbar-track {
background: transparent;
}
#doubao-nav-sidebar .nav-list::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.2);
border-radius: 4px;
}
/* 可选:鼠标不在导航栏时,让整个导航栏更半透明 */
#doubao-nav-sidebar {
background: rgba(255, 255, 255, 0.7);
}
#doubao-nav-sidebar:hover {
background: rgba(255, 255, 255, 0.98);
}
/* 确保点击穿透问题?不,我们不需要点击穿透,因为窄条时也没东西可点,悬停后才可点 */
manifest.json
{
"manifest_version": 3,
"name": "豆包对话导航助手",
"version": "1.0",
"description": "在豆包的AI对话页面上添加一个侧边导航栏,方便快速定位历史问题。",
"permissions": [
"activeTab"
],
"content_scripts": [
{
"matches": ["*://www.doubao.com/*"],
"js": ["content.js"],
"css": ["styles.css"],
"run_at": "document_end"
}
]
}
这是我第一次尝试开发浏览器插件。
当然也遇到了很多问题,
第一个问题
这个代码也不能保证一直可以用,今天我用的时候就出现了问题,就是我的导航栏直接清空了,刷新也不行,然后我发现是豆包他一定时间会更新一次,因为这个导航的本质是去找到那个问题模块,也就是类,class。这个class更新的时候也会变,所以这个代码并不可以一直使用,豆包更新的时候就要通过检查台再去找一下对应的class并修改。
第二个问题
我对于JS的学习还不够深入,我的理想模型是和deep seek一样,只有问题的导航,但是我的这个导航不仅有问题还有对应的答案,刚开始我是有点烦的,这并没有达到我的理想目标,但是我的技术有限,只能到这一步,就将就着用了,用了一段时间发现还挺好的,有时候用户的问题也是比较长的,从问题到答案也是很长的要去滑动鼠标,而我的这个插件可以直接到对应的答案,所以我现在挺喜欢用的。
最后
欢迎大家使用我的插件,并帮我分析,给我一些用后的感受,如果有更好用的这样类型的插件也可以给我分享一下,希望有大神看到后可以帮我看看怎么修改才能和deep seek一样,我的代码哪里有问题可以给我指出来,
虽然功能还比较简单,但已经实现了基本的对话导航功能。
后面准备继续增加:
- 自定义 AI 网站
- 深色模式
- 快捷键唤起
- 多平台支持
如果有建议欢迎交流。
更多推荐



所有评论(0)