当前位置: 首页 > news >正文

鸿蒙PC:鸿蒙electron跨端框架PC链接雷达实战:把本地收藏夹升级成可巡检的链接管理面板

前言

欢迎加入鸿蒙PC开发者社区,共同打造开发者工具生态:鸿蒙PC开发者社区 :https://harmonypc.csdn.net/

项目开源地址:https://AtomGit.com/lqjmac/ele_lianjieleida

浏览器收藏夹能保存链接,但不擅长保存判断。

很多链接刚收藏时很重要,过几天再看,只剩下一串 URL 和一个模糊标题。到底为什么收藏、是否读完、能不能引用、下次什么时候复查,都很难说清。

所以这个工具叫链接雷达

它不是替代浏览器收藏夹,而是给本地链接加上状态、摘要、复查点和导出能力。

适合这些场景:

  • 项目调研链接需要持续复查
  • 技术资料链接要整理引用说明
  • 文章素材链接要记录上下文
  • 本地收藏需要导出成 Markdown

链接管理的关键不是“存了多少”,而是“下一次打开时还能不能判断它有没有用”。

本文会按链接巡检思路拆解 Vue3 页面、状态模型、Electron 桥接、剪贴板复制、Markdown 导出和桌面端构建检查。

一、链接雷达先解决上下文丢失

1.1 收藏链接为什么还会丢

链接丢失不一定是 URL 不见了。

更多时候是上下文消失了。

丢失内容具体表现链接雷达的处理
收藏原因不知道当时为什么保存增加摘要和主题
阅读状态不知道是否看完增加待扫描、已确认、需复查
引用价值不知道能不能写进文档增加高亮和引用说明
复查时间不知道何时再看增加 nextReview

这也是为什么第一版重点不做浏览器同步。

先把链接判断记录做扎实更重要。

1.2 第一版的轻闭环

链接雷达先做五件事:

  1. 收进一个链接条目
  2. 标记链接类型和当前状态
  3. 写摘要、高亮和复查时间
  4. 复制链接说明
  5. 导出 Markdown 巡检记录

这条链路可以覆盖大部分个人资料整理场景。

二、文件分工围绕链接巡检

2.1 组件职责

文件职责链接场景里的作用
Home.vue页面总装组织雷达面板、列表和编辑区
LinkSidebar.vue左侧筛选搜索、类型、状态统计
LinkList.vue链接列表展示链接标题、状态、摘要
LinkEditor.vue编辑区URL、来源、主题、复查点
useLinks.ts状态层本地保存、筛选、排序
useNativeBridge.ts桥接层复制、保存、通知

链接工具的组件不需要复杂,但要把 URL、状态和摘要分开。

这样后续才方便做有效性检测。

2.2 页面不直接处理原生能力

const{copyText,exportMarkdown,notify,isNativeRuntime,}=useNativeBridge();

页面只调用语义方法。

运行时差异由桥接层兜住。

三、页面结构图

3.1 链接雷达结构图

这张图表现的是链接从收集、扫描、确认到导出的过程。

3.2 为什么用雷达感界面

链接巡检像是在一堆信息源里扫描信号。

有些链接只是待读,有些需要复查,有些可以直接引用。

区域作用视觉重点
左侧链接类型和搜索暗色背景下保持清晰
中间链接信号列表状态边线要明显
右侧链接判断摘要和高亮优先
顶部复制和导出按钮不遮挡内容

暗色不是为了炫,而是让状态色更容易被识别。

四、数据模型要保存链接判断

4.1 字段设计

字段含义示例
title链接标题Electron 窗口文档
url链接地址https://www.electronjs.org
source来源官方文档、调研文章
topic主题桌面窗口控制
category类型待读链接、引用参考
state状态待扫描、已确认、需复查
summary摘要说明这个链接能解决什么
highlights高亮值得引用的结论
nextReview下次复查版本更新后

链接条目必须保存 URL,但列表层不能只显示 URL。

否则用户仍然要重新理解。

4.2 TypeScript 类型

exporttypeLinkState='scanning'|'confirmed'|'reviewing';exporttypeLinkCategory=|'reading'|'signal'|'followup'|'reference';exportinterfaceLinkItem{id:string;title:string;url:string;source:string;topic:string;category:LinkCategory;state:LinkState;keywords:string;summary:string;highlights:string;nextReview:string;content:string;pinned:boolean;archived:boolean;createdAt:number;updatedAt:number;}

这份类型为后续做链接有效性检测预留了空间。

五、状态和类型要像巡检

5.1 文案映射

constcategoryLabelMap:Record<LinkCategory,string>={reading:'待读链接',signal:'线索页面',followup:'跟进流程',reference:'引用参考',};conststateLabelMap:Record<LinkState,string>={scanning:'待扫描',confirmed:'已确认',reviewing:'需复查',};

这些文案决定用户如何理解列表。

不要把链接工具写成普通笔记工具。

5.2 状态解释

状态含义下一步动作
待扫描刚收进来,还没读打开并补摘要
已确认内容可引用或可继续用复制说明或导出
需复查时效、来源或结论待确认设置复查点

状态越清晰,链接越不会堆成信息噪声。

六、默认链接要像真实调研

6.1 示例数据

exportconstseedLinks:LinkItem[]=[{id:'link-electron-window',title:'Electron BrowserWindow 配置',url:'https://www.electronjs.org/docs/latest/api/browser-window',source:'Electron 官方文档',topic:'桌面窗口控制',category:'reference',state:'confirmed',keywords:'Electron,BrowserWindow,preload,contextIsolation',summary:'用于确认窗口尺寸、预加载脚本和安全隔离配置。',highlights:'BrowserWindow 的 webPreferences 决定页面和主进程能力边界。',nextReview:'Electron 版本升级后',content:'这条链接适合放在窗口初始化和桥接能力说明附近。',pinned:true,archived:false,createdAt:Date.now()-3600_000,updatedAt:Date.now(),},];

这条默认链接带有明确用途。

读者打开工具就能理解它为什么被收藏。

6.2 默认数据覆盖

默认数据至少覆盖:

  • 官方文档链接
  • 调研文章链接
  • 待扫描链接
  • 需复查链接
  • 可引用链接

这样才能测试不同状态的显示效果。

七、本地保存链接资料

7.1 读取数据

constSTORAGE_KEY='lianjie-leida-links:v1';functionloadLinks():LinkItem[]{if(typeofwindow==='undefined')returnseedLinks;try{constraw=window.localStorage.getItem(STORAGE_KEY);if(!raw)returnseedLinks;constparsed=JSON.parse(raw);returnArray.isArray(parsed)?parsed:seedLinks;}catch{returnseedLinks;}}

链接工具也要防止本地缓存损坏。

不能因为一条坏数据让整个应用打不开。

7.2 新建链接

functioncreateLink(){constnow=Date.now();constlink:LinkItem={id:`link-${now}-${Math.random().toString(16).slice(2)}`,title:'新的链接',url:'',source:'',topic:'',category:'reading',state:'scanning',keywords:'',summary:'',highlights:'',nextReview:'',content:'',pinned:false,archived:false,createdAt:now,updatedAt:now,};links.value=[link,...links.value];currentLinkId.value=link.id;schedulePersist();}

新建时默认放到待读链接。

符合“先收进来,再判断”的工作流。

八、筛选要支持 URL 和主题

8.1 可见链接

constsearchTerm=ref('');constactiveCategory=ref<'all'|LinkCategory>('all');constvisibleLinks=computed(()=>{constkeyword=searchTerm.value.trim().toLowerCase();returnlinks.value.filter(link=>{if(link.archived)returnfalse;if(activeCategory.value!=='all'&&link.category!==activeCategory.value){returnfalse;}if(!keyword)returntrue;return[link.title,link.url,link.source,link.topic,link.keywords,link.summary,].join(' ').toLowerCase().includes(keyword);}).sort(sortLinks);});

搜索 URL 很重要。

有时候用户只记得域名,不记得标题。

8.2 排序规则

functionsortLinks(a:LinkItem,b:LinkItem){if(a.pinned!==b.pinned)returna.pinned?-1:1;constorder:Record<LinkState,number>={reviewing:0,scanning:1,confirmed:2,};if(a.state!==b.state){returnorder[a.state]-order[b.state];}returnb.updatedAt-a.updatedAt;}

需复查链接优先出现。

链接失效或结论过期的风险比普通待读更高。

九、列表卡片不要只放 URL

9.1 链接卡片

<template> <button class="link-card" :class="link.state" @click="$emit('select', link.id)"> <span class="status">{{ stateLabelMap[link.state] }}</span> <strong>{{ link.title || '未命名链接' }}</strong> <span class="domain">{{ domain }}</span> <p>{{ excerpt(link.summary || link.content) }}</p> </button> </template>

URL 可以显示域名,不必在卡片里完整铺开。

完整 URL 放进编辑区更合适。

9.2 解析域名

functiongetDomain(url:string){try{returnnewURL(url).hostname;}catch{return'未设置链接';}}

域名比完整 URL 更适合快速扫描。

如果 URL 不合法,也要给出稳定兜底。

十、编辑器补足链接上下文

10.1 编辑字段

<template> <article class="link-editor"> <input :value="link.title" placeholder="链接标题" @input="updateField('title', $event)" /> <input :value="link.url" placeholder="https://..." @input="updateField('url', $event)" /> <input :value="link.source" placeholder="来源" @input="updateField('source', $event)" /> <input :value="link.topic" placeholder="主题" @input="updateField('topic', $event)" /> <textarea :value="link.summary" placeholder="写清这个链接解决什么问题" @input="updateField('summary', $event)" /> </article> </template>

链接编辑器的核心是补上下文。

URL 本身只是入口。

10.2 URL 校验提示

constisValidUrl=computed(()=>{if(!currentLink.value?.url.trim())returnfalse;try{newURL(currentLink.value.url);returntrue;}catch{returnfalse;}});

初始版本不一定要阻止保存。

但可以提示 URL 是否规范。

十一、复制动作要区分目标

11.1 摘要复制

asyncfunctioncopyLinkSummary(){if(!currentLink.value)return;consttext=currentLink.value.summary||currentLink.value.highlights||currentLink.value.url||currentLink.value.title;constok=awaitcopyText(text);if(ok){showFeedback('链接摘要已复制');awaitnotify('链接雷达','当前链接摘要已经复制到剪贴板');}}

这个顺序适合资料流转。

如果用户只想复制 URL,后续可以再加单独按钮。

11.2 可扩展复制菜单

后续可以扩展三个复制入口:

  1. 复制 URL
  2. 复制引用说明
  3. 复制 Markdown 卡片

第一版保持一个按钮,先降低复杂度。

十二、导出 Markdown 像巡检记录

12.1 导出结构

functionbuildLinkMarkdown(link:LinkItem){return[`#${link.title||'未命名链接'}`,'',`- URL:${link.url||'未设置'}`,`- 类型:${categoryLabelMap[link.category]}`,`- 状态:${stateLabelMap[link.state]}`,`- 来源:${link.source||'未设置'}`,`- 主题:${link.topic||'未设置'}`,`- 关键词:${link.keywords||'未设置'}`,`- 下次复查:${link.nextReview||'未设置'}`,'','## 摘要','',link.summary||'暂无摘要','','## 关键高亮','',link.highlights||'暂无高亮','','## 备注','',link.content||'暂无正文',].join('\n');}

导出的链接记录可以直接进入调研文档。

12.2 安全文件名

functionsafeLinkFileName(value:string){return(value.trim()||'链接记录').replace(/[\\/:*?"<>|]/g,'-').slice(0,80);}

URL 不适合直接作为文件名。

用标题更稳。

十三、桥接层处理剪贴板和保存

13.1 统一接口

exportfunctionuseNativeBridge(){asyncfunctioncopyText(text:string){if(!text.trim())returnfalse;if(window.desktopBridge?.copyText){returnwindow.desktopBridge.copyText(text);}awaitnavigator.clipboard.writeText(text);returntrue;}return{copyText,exportMarkdown,notify,};}

这层可以复用到其他桌面工具。

13.2 预加载能力

const{contextBridge,ipcRenderer}=require('electron');contextBridge.exposeInMainWorld('desktopBridge',{copyText:text=>ipcRenderer.invoke('copy-text',text),saveMarkdown:data=>ipcRenderer.invoke('save-markdown',data),showNotification:data=>ipcRenderer.invoke('show-notification',data),});

预加载脚本是页面和原生能力之间的边界。

相关概念可以参考 Electron contextBridge。

十四、主进程加载本地资源

14.1 窗口配置

const{app,BrowserWindow}=require('electron');constpath=require('path');functioncreateWindow(){constwin=newBrowserWindow({width:1225,height:850,minWidth:980,minHeight:720,title:'链接雷达',webPreferences:{preload:path.join(__dirname,'preload.js'),contextIsolation:true,nodeIntegration:false,},});win.loadFile(path.join(__dirname,'..','dist','index.html'));}app.whenReady().then(createWindow);

窗口标题要和工具一致。

这能减少调试时的混乱。

14.2 构建命令

npmrun buildtest-fdist/index.htmlfinddist/assets-typef|sort

资源存在是运行的前提。

不要只看开发环境能不能打开。

十五、雷达视觉要克制

15.1 暗色主题

.link-radar{min-height:100%;display:grid;grid-template-columns:300pxminmax(0,1fr)380px;background:#0c131d;color:#edf9f7;}.link-card{border:1px solidrgba(127,255,212,0.22);border-left:4px solidrgba(127,255,212,0.65);background:#111b27;border-radius:8px;padding:14px;}.link-card.reviewing{border-left-color:#ffcc66;}

暗色主题要注意对比度。

不要为了氛围牺牲可读性。

15.2 URL 显示

.domain{display:inline-block;max-width:100%;color:#7fffd4;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}

长 URL 很容易撑破布局。

列表里只显示域名更安全。

十六、滚动和窗口体验

16.1 布局滚动

html, body, #app{width:100%;height:100%;margin:0;}.link-radar{height:100vh;min-height:0;overflow:hidden;}.link-list, .link-editor{min-height:0;overflow:auto;}

链接列表可能很长,编辑区内容也可能很多。

两边都要能滚动。

16.2 原生窗口栏

链接雷达不建议在页面里自绘窗口按钮。

原生窗口栏可以保证最小化、最大化、关闭行为稳定。

业务页面专注链接内容即可。

十七、发布前检查

17.1 功能检查

发布前检查:

  1. 标题和窗口都显示链接雷达
  2. 默认链接包含真实 URL
  3. 搜索标题、域名、关键词都能命中
  4. URL 不合法时页面不崩溃
  5. 复制摘要可以写入剪贴板
  6. 导出 Markdown 包含 URL 和状态
  7. 长链接不会撑破卡片

这些点覆盖链接工具的主要风险。

17.2 文章检查表

检查项结果说明
图片通过结构图可显示
表格通过覆盖对比、字段、检查
代码块通过覆盖类型、组件、桥接、样式
链接通过正文和资源区包含有效链接
投票引导通过文末保留

链接类工具最怕列表看起来很多,实际没有任何可复用判断。

十八、后续扩展方向

18.1 链接有效性检测

后续可以补:

  • 定时检查链接是否可访问
  • 记录 HTTP 状态码
  • 标记重定向
  • 保存网页标题快照
  • 给过期链接加复查提醒

这些能力可以逐步做。

18.2 引用管理

还可以增加:

  1. 复制 Markdown 引用
  2. 复制 HTML 链接
  3. 按项目导出链接包
  4. 给链接添加可信度评分
  5. 按主题生成调研报告

这会让链接雷达从收藏工具变成调研辅助工具。

总结

链接雷达解决的不是“保存 URL”,而是保存链接背后的判断。

通过状态、主题、摘要、复查点、复制和导出,它把本地收藏变成可巡检、可流转的桌面资料面板。

后续如果继续增强,我会优先做链接有效性检测和 Markdown 引用复制。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

  • 鸿蒙PC开发者社区:https://harmonypc.csdn.net/
  • OpenHarmony 文档:https://docs.openharmony.cn/
  • Electron 官方文档:https://www.electronjs.org/docs/latest/
http://www.jsqmd.com/news/874252/

相关文章:

  • 08-系统技术架构师必备——分布式系统理论与数据一致性
  • Python异步编程深度解析:从asyncio到实战应用
  • 收藏!小白程序员这样学大模型,从入门到精通全攻略!
  • 2026年厨下净热一体机厂家实力排行及地址盘点:中央净水机、全能冰泉机、厨下反渗透净水机、厨下净热一体机、大流量净水机选择指南 - 优质品牌商家
  • 2026年当前浙江省单位食堂承包深度选型:为何食润康餐饮成为全链条服务标杆? - 2026年企业推荐榜
  • ES 模块:JavaScript 模块化的标准方案
  • 小波分析多尺度数据融合算法应用【附算法】
  • Harness与Agent SDK的边界划分:最佳实践
  • 学 Simulink—— 双定子永磁同步电机(DS‑PMSM)的协同控制与转矩提升仿真(带 MATLAB 脚本(直接运行))
  • 2026年5月陕西控制电缆采购聚焦:西安华联电力电缆有限公司为何成为优选 - 2026年企业推荐榜
  • 回归模型.
  • 2026酒店民宿装修设计优质服务商推荐指南:厂房装修设计、商业空间装修设计、四川公装公司、四川公装装修公司、展厅装修设计选择指南 - 优质品牌商家
  • 5分钟搞定视频号批量下载:开源工具让效率提升20倍
  • 如何高效使用Obsidian Text Generator插件:实战进阶指南
  • 国曙GOSHINE正式亮相:一家人力资源服务机构的“长期主义”转向!
  • 绵阳本地围栏厂家实测排行:绵阳庭院大门厂家、绵阳快速卷闸门厂家、绵阳智能门窗、绵阳智能门窗厂家、绵阳水晶卷帘门厂家选择指南 - 优质品牌商家
  • Rust Trait系统设计模式:实现灵活的多态和代码复用
  • 2026荣县名表回收优质商家推荐榜:自贡名表回收、荣县黄金回收、金条黄金回收电话、附近黄金回收、高价名表回收、高价黄金回收选择指南 - 优质品牌商家
  • LeetCode 1424:对角线遍历 II | 前缀和分组
  • AI系列【仅供参考】:TRAE 支持自定义模型了,配置个 DeepSeek V4 试试
  • 【应用实战】基于Dify与多Agent的凭证与档案管理
  • API接口签名验证实战
  • 【火电机组、风能、储能】高比例风电电力系统储能运行及配置分析(Matlab代码实现)
  • 数据科学实践案例与项目管理
  • 大模型从0训练LLaMA全流程实战——基于昇腾910B集群
  • JWT令牌安全实践详解
  • AI系列【仅供参考】:周末用笔记本搞点大事:手把手教学部署 1.5、7B 版本 DeepSeek 智能助手
  • 黄仁勋放话:AI基建要烧掉4万亿美元 谁买单?
  • LeetCode 930:和相同的二元子数组 | 前缀和与哈希表
  • 从微服务到 Agent 服务:架构思维的迁移