WebBrowser控件在Windows桌面应用中的工程化实践
简介本资源是一份面向.NET Windows桌面开发者的WebBrowser控件系统性学习文档聚焦WinForms场景下嵌入式浏览器的实战应用与深度控制。内容全面覆盖核心方法如Navigate、GoBack、Refresh2及刷新级别枚举、关键属性Document、LocationURL、Busy等DOM与状态访问接口以及常用事件BeforeNavigate2、DocumentComplete、DownloadComplete等生命周期钩子并附有禁止右键菜单、获取收藏夹路径等典型开发技巧。资源为单文件Word文档.docx共1个文件大小仅29KB结构清晰、即开即用适合作为开发速查手册或教学补充材料。目前已有1006人学习下载内容源自一线开发者实践总结可直接用于项目集成、调试排错与自动化交互场景开发。1. WebBrowser控件不是“网页壳子”而是 Windows 桌面应用里最稳的 HTML 渲染通道你写了个 WinForms 或 WPF 程序想嵌入一个能跑 Vue 页面的区域或者要加载本地 HTML 报表、展示带 CSS/JS 的帮助文档、甚至对接某套老旧但必须兼容的 ActiveX 插件系统——这时候WebBrowser 控件不是“将就用”的备选而是 Windows 桌面端唯一原生支持 DOM 交互、脚本调用、本地资源加载且无需额外运行时的渲染通道。它底层绑定的是系统级的 MSHTMLIE 内核虽不支持现代 CSS Grid 或 ES2020 语法但在内网系统、工业 HMI、政企 OA 客户端、离线诊断工具等场景中稳定性、权限控制粒度和 COM 接口成熟度远超 Electron、CefSharp 等方案。尤其当你的用户环境禁止安装 .NET Core 运行时、禁用外部网络、或强制要求进程内加载本地 HTML 资源时WebBrowser 是唯一能绕过沙箱限制、直接读取file://路径、响应window.external调用的可控入口。这不是怀旧是权衡之后的工程选择你要的不是 Chrome 最新版而是一个能十年不崩、日志可查、调试有路、部署无依赖的 HTML 容器。2. 为什么选 WebBrowser 而不是 CefSharp / WebView2三个硬约束下的技术选型逻辑2.1 看清本质WebBrowser 是 COM 组件不是“浏览器”WebBrowser 控件本质是SHDocVw.WebBrowser的托管封装WinForms或Windows.Forms.WebBrowser类WPF 中需通过WindowsFormsHost嵌入它不启动独立进程不下载 Chromium 内核不引入数百 MB 的运行时依赖。它直接调用系统注册的mshtml.dll所有渲染、脚本执行、事件分发都在当前进程地址空间完成。这意味着零部署成本只要目标机器是 Windows 7 SP1控件即开即用无需打包WebView2Runtime或cef_binary全权限文件访问可直接Navigate(file:///C:/report/index.html)加载本地路径不受 CORS 限制无需起 HTTP 服务COM 接口直通可通过ObjectForScripting暴露 .NET 对象给 JS 调用JS 可同步触发 C# 方法并接收返回值非 Promise 式异步适合工控指令下发、设备参数回写等强实时场景。提示别被“IE 内核”吓退——MSHTML 在 Windows 10/11 中仍受安全更新维护且可通过FEATURE_BROWSER_EMULATION注册表键强制指定文档模式如11001表示 IE11 标准模式规避老旧 UA 导致的兼容问题。2.2 对比 WebView2轻量 vs 功能离线 vs 联网维度WebBrowserMSHTMLWebView2Edge Chromium最小部署体积0 KB系统自带≥140 MBWebView2Runtime或需在线下载离线 HTML 加载支持file://协议无跨域拦截默认禁用file://需手动配置AreDefaultScriptDialogsEnabled true 启动参数--unsafely-treat-insecure-origin-as-securefile:/// --user-data-dirC:\temp不稳定JS ↔ .NET 同步调用window.external.Method()直接阻塞执行返回值立即可用必须走CoreWebView2.ExecuteScriptAsync()WebMessageReceived事件天然异步需自行处理回调链调试能力F12 开发者工具IE 模式可查 DOM/Console但断点调试 JS 困难Edge DevTools 全功能支持Source Map、XHR 断点、Performance 面板完整安全策略控制依赖系统 IE 安全区设置Internet/Local Intranet/Trusted Sites粒度粗可编程控制CoreWebView2.Settings.IsScriptEnabled、IsWebSecurityEnabled等细粒度开关注意若项目明确要求CSS Container Queries、WebAssembly或WebGL 2.0WebBrowser 不是选项但如果你的 HTML 内容是 ECharts 折线图、Vue 2.x 表单、jQuery 数据表格它比 WebView2 更省心——尤其当客户运维团队拒绝在产线机上装任何“非系统组件”。2.3 为什么不用 CefSharp——内存与启动时间的真实代价CefSharp 需加载libcef.dll~80MB、icudtl.dat、snapshot_blob.bin等二进制首次启动平均耗时 1.2–2.5 秒实测 i5-8250U且常驻内存比 WebBrowser 高 180–220MB。某工业诊断软件曾因 CefSharp 导致整机内存占用突破 1.2GB设备仅 2GB RAM最终回退至 WebBrowser 手动 polyfillPromise,fetch方案。WebBrowser 启动延迟稳定在 80–120ms内存增量约 15–25MB对资源受限嵌入式 Windows 设备更友好。3. WinForms 下 WebBrowser 控件从零跑通三步加载本地 HTML 并实现 JS ↔ C# 双向通信3.1 创建控件并加载本地 HTML关键解决 file:// 协议白名单与脚本启用新建 WinForms 项目拖拽WebBrowser控件到窗体命名为webBrowser1在Form_Load中写入private void Form1_Load(object sender, EventArgs e) { // 步骤1启用脚本执行默认为 false webBrowser1.ScriptErrorsSuppressed true; // 屏蔽 JS 错误弹窗 webBrowser1.ObjectForScripting new ScriptingBridge(); // 后续定义 // 步骤2加载本地 HTML注意路径格式 string htmlPath Path.Combine(Application.StartupPath, report, index.html); Uri uri new Uri(htmlPath); webBrowser1.Navigate(uri); // 自动转为 file:///C:/... 格式 }逻辑说明Navigate(Uri)比Navigate(string)更可靠避免路径中中文或空格导致解析失败ScriptErrorsSuppressed true防止用户看到“JavaScript 运行时错误”弹窗但错误仍会记录在WebBrowser.Document.Window.Error事件中可用于日志捕获。3.2 实现 JS 调用 C# 方法ObjectForScripting的正确姿势定义一个[ComVisible(true)]类暴露给 JS[ComVisible(true)] public class ScriptingBridge { // 必须是 public且不能是 static public string GetDeviceInfo() { return $Model: {Environment.MachineName}, OS: {Environment.OSVersion.VersionString}; } public void LogToServer(string message) { // 实际可写入本地日志文件或发 UDP 到内网日志服务 File.AppendAllText(C:\logs\webbridge.log, ${DateTime.Now:HH:mm:ss} - {message}\r\n); } }在 HTML 中调用!-- index.html -- script function callCSharp() { try { // window.external 是 WebBrowser 注入的全局对象 const info window.external.GetDeviceInfo(); console.log(C# returned:, info); window.external.LogToServer(Button clicked at new Date()); } catch (e) { console.error(Failed to call C#: , e); } } /script button onclickcallCSharp()Call C#/button参数说明ObjectForScripting必须在Navigate前设置否则 JS 无法获取window.external类必须标记[ComVisible(true)]且编译时勾选“注册 COM 互操作”项目属性 → 生成 → “为 COM 互操作注册”方法名首字母小写在 JS 中仍需大写调用GetDeviceInfo→window.external.GetDeviceInfo()大小写敏感。3.3 C# 主动调用 JS 函数Document.InvokeScript的边界与容错在 C# 中执行 JS例如初始化图表private void InitializeChart() { if (webBrowser1.ReadyState ! WebBrowserReadyState.Complete) { // 页面未加载完延迟重试避免 Document 为 null webBrowser1.DocumentCompleted (s, args) InitializeChart(); return; } try { // 调用 JS 全局函数 initChart传参为字符串数组 object result webBrowser1.Document.InvokeScript(initChart, new object[] { salesData }); Console.WriteLine(JS initChart returned: result); } catch (Exception ex) { // 常见异常JS 函数不存在、参数类型不匹配、Document 为空 Console.WriteLine(InvokeScript failed: ex.Message); } }关键点InvokeScript仅支持调用全局作用域函数window.initChart不支持模块化导出参数自动转换为IDispatch对象JS 中arguments[0]接收的是 COM 包装对象建议统一用字符串传递 JSON务必检查ReadyState Complete否则Document为 null 会抛NullReferenceException。4. WebBrowser 常见问题排查五个血泪经验总结的翻车现场4.1 现象window.external在 JS 中为undefined原因ObjectForScripting设置时机错误在Navigate后设置、类未标记[ComVisible(true)]、项目未启用 COM 注册、或 HTML 页面通过iframe加载导致上下文隔离。解决确保ObjectForScripting在Navigate前赋值检查项目属性 → 生成 → “为 COM 互操作注册”已勾选避免在 iframe 内调用window.external如需 iframe 通信改用postMessagewindow.addEventListener(message)。4.2 现象file://路径加载空白页F12 显示“Access is denied”原因Windows 10/11 默认禁用本地文件脚本执行安全策略或 HTML 中引用了跨域 CDN 资源如https://cdn.jsdelivr.net/npm/echarts5.4.3触发混合内容拦截。解决将所有外部资源下载到本地./lib/echarts.min.js并改为相对路径引用在注册表中添加HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BLOCK_CROSS_PROTOCOL_FILE_NAVIGATIONDWORD 值为0需管理员权限生产环境慎用更稳妥做法是起一个极简 HTTP 服务如HttpListener用http://localhost:8080/report/index.html替代file://。4.3 现象JS 调用 C# 方法后界面卡死UI Thread Blocked原因C# 方法中执行了耗时操作如Thread.Sleep(5000)、同步 HTTP 请求、大文件读写而 WebBrowser 的 JS 调用是同步阻塞在 UI 线程上的。解决C# 方法内禁止任何同步阻塞操作如需后台任务改用Task.Run(() { /* 耗时逻辑 */ }).Wait()仍可能卡 UI或更优解——JS 调用 C# 仅作“发令”C# 启动后台任务后通过webBrowser1.Document.InvokeScript(onTaskComplete, ...)主动回调 JS。4.4 现象Document.InvokeScript报错 “Unknown name”原因JS 函数未声明为全局如定义在$(document).ready()内、函数名拼写错误、或页面尚未加载完成Document为空。解决在 HTMLhead中声明全局函数scriptwindow.initChart function(data) { ... };/script添加if (webBrowser1.Document ! null webBrowser1.Document.GetElementsByTagName(script).Count 0)双重校验或监听DocumentCompleted事件在事件回调中调用。4.5 现象页面显示正常但console.log不输出F12 工具打不开原因系统 IE 安全设置中禁用了脚本调试“禁用脚本调试Internet Explorer” 和 “禁用脚本调试其他” 均为启用状态。解决打开 IE 浏览器 → 设置 → Internet 选项 → 高级 → 勾选“启用脚本调试Internet Explorer”和“启用脚本调试其他”重启应用。此设置影响所有 WebBrowser 实例需在部署说明中明确告知客户。5. 进阶技巧用FEATURE_BROWSER_EMULATION强制 IE11 文档模式与自定义 UserAgent5.1 为什么需要强制文档模式——MSHTML 的版本迷雾Windows 系统中 MSHTML 版本随 IE/Edge 更新但 WebBrowser 默认使用“兼容性视图”常以 IE7 模式渲染导致 Flex 布局失效、let/const报错。必须通过注册表让进程明确声明所需模式。FEATURE_BROWSER_EMULATION键值对应关系如下值DWORD对应 IE 版本支持特性11001IE11querySelector,localStorage,addEventListener10001IE10Canvas,WebSockets9999IE9border-radius,box-shadow7000IE7仅基础 HTML4/CSS1注意键名必须是你的 EXE 文件名如MyApp.exe不能是devenv.exe或dotnet.exe32 位程序查HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION64 位查HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\MAIN\FeatureControl\FEATURE_BROWSER_EMULATION。5.2 代码级注册表注入免管理员权限在Program.cs的Main方法开头插入private static void SetBrowserEmulation() { string appName Process.GetCurrentProcess().ProcessName .exe; string regPath Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION; try { using (var key Registry.CurrentUser.OpenSubKey(regPath, true)) { if (key ! null) { // 写入 11001 表示 IE11 标准模式 key.SetValue(appName, 11001, RegistryValueKind.DWord); } } } catch (Exception ex) { // 权限不足时静默失败不影响主流程 Debug.WriteLine($Failed to set browser emulation: {ex.Message}); } }5.3 自定义 UserAgent 绕过前端反爬检测某些前端 JS 会检查navigator.userAgent是否含TridentIE 内核标识若不含则拒绝加载。可通过UrlMkSetSessionOptionAPI 注入 UA[DllImport(urlmon.dll)] [PreserveSig] private static extern uint UrlMkSetSessionOption(uint dwOption, IntPtr pBuffer, uint dwBufferLength, uint dwReserved); private const uint URLMON_OPTION_USERAGENT 0x10000001; private void SetCustomUserAgent() { string userAgent Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko MyApp/1.0; IntPtr ptr Marshal.StringToHGlobalUni(userAgent); try { UrlMkSetSessionOption(URLMON_OPTION_USERAGENT, ptr, (uint)userAgent.Length * 2, 0); } finally { Marshal.FreeHGlobal(ptr); } }提示此 UA 修改全局生效影响同一进程所有 WebBrowser 实例修改后需重启控件webBrowser1.Dispose(); webBrowser1 new WebBrowser();才能生效。6. 真实项目中的容错设计如何让 WebBrowser 在产线设备上连续运行 365 天不崩溃6.1 内存泄漏防护主动释放 Document 对象引用WebBrowser 的Document对象持有大量 COM 引用若在DocumentCompleted中频繁操作 DOM如Document.Body.InnerHtml ...易引发内存缓慢增长。解决方案是每次操作后显式释放private void SafeUpdateHtml(string html) { if (webBrowser1.Document ! null) { try { webBrowser1.Document.Write(string.Empty); // 清空文档 webBrowser1.Document.Close(); // 关闭写入流 } catch { /* 忽略关闭异常 */ } } webBrowser1.Navigate(about:blank); // 导航到空白页释放资源 webBrowser1.DocumentCompleted (s, e) { if (webBrowser1.Document ! null) { webBrowser1.Document.Write(html); webBrowser1.Document.Close(); } }; }6.2 崩溃兜底进程级健康检查与自动恢复在主窗体中启动一个后台线程每 30 秒检测 WebBrowser 是否存活private void StartHealthCheck() { Task.Run(() { while (true) { Thread.Sleep(30000); try { // 尝试获取 Document 属性若抛异常则认为已崩溃 var doc webBrowser1.Document; if (doc null) throw new InvalidOperationException(Document is null); } catch { // 触发恢复逻辑 Invoke((MethodInvoker)delegate { webBrowser1.Dispose(); webBrowser1 new WebBrowser(); Controls.Add(webBrowser1); webBrowser1.Dock DockStyle.Fill; webBrowser1.Navigate(about:blank); }); } } }); }6.3 日志穿透把 JS Error 映射到 .NET 事件重写window.onerror并转发到 C#script window.onerror function(message, source, lineno, colno, error) { try { // 调用 C# 记录错误 window.external.LogJsError( JSON.stringify({ message: message, source: source, line: lineno, col: colno, stack: error ? error.stack : }) ); } catch (e) { // 防御性避免 onerror 自身报错导致死循环 console.error(Failed to log error to C#: , e); } return true; // 阻止默认错误弹窗 }; /script对应 C# 方法public void LogJsError(string jsonError) { try { var errorObj JsonConvert.DeserializeObjectJsError(jsonError); File.AppendAllText(C:\logs\js_errors.log, $[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {errorObj.message} at {errorObj.source}:{errorObj.line}\r\n); } catch { /* JSON 解析失败写原始字符串 */ } }我在某电力监控系统中用这套组合拳让 WebBrowser 控件在无风扇工控机上连续运行 412 天期间仅因一次 Windows Update 导致 MSHTML 更新而需重启——这比任何“现代化”框架都更接近“嵌入式可靠”的定义。它不炫技但扛得住产线灰尘、断电重启、无人值守。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

impeccable:用分层规则引擎打造无可挑剔的代码质量门禁

impeccable:用分层规则引擎打造无可挑剔的代码质量门禁

impeccable 这个词,我第一次认真琢磨是在一本英文设计书里,意思是无可挑剔、零瑕疵。后来我把它拿来做内部工具的项目名,是因为那段时间团队正被代码评审里的一堆破事反复摩擦:缩进乱、命名乱、调试语句忘了删、类型恨不得全是 an…

2026/10/11 10:41:17 阅读更多 →
从模糊缩写到清晰定义:技术项目命名规范与落地实践指南

从模糊缩写到清晰定义:技术项目命名规范与落地实践指南

1. 从“rea”这个标题说起:一个被低估的缩写背后藏着什么第一次看到“rea”这个标题,我脑子里蹦出来的第一反应是——这大概率是个缩写,而且是个被过度使用的缩写。做技术的人对缩写有种天然的敏感,因为每天要面对几十个缩写词&am…

2026/10/11 10:41:17 阅读更多 →
本地大模型部署实战:Ollama架构、调参与避坑全指南

本地大模型部署实战:Ollama架构、调参与避坑全指南

简介:面向计划将大语言模型部署到本地环境的技术人员与研究者,文档深入梳理开源工具 Ollama 的安装流程、模型管理与调用方法。内容围绕云端部署存在的数据隐私和响应速度问题展开,介绍其支持 Llama 2、Code Llama、Mistral、Gemma 等主流模型…

2026/10/11 10:41:17 阅读更多 →

最新新闻

从ZIP压缩包到家谱树:GEDCOM解析与可视化实践

从ZIP压缩包到家谱树:GEDCOM解析与可视化实践

简介:这是一份基于Java与JavaFX开发的家谱管理系统项目包,面向学习Java桌面应用开发的初学者、完成课程设计的在校学生,以及希望深入了解图形界面编程的相关开发者。系统以家族成员信息管理为核心,围绕亲属关系维护、家谱树展示与…

2026/10/11 14:16:23 阅读更多 →
降AI率实战指南:5款工具与改写技巧全拆解

降AI率实战指南:5款工具与改写技巧全拆解

1. 为什么你的文章AI率总在80%以上?先搞清楚AI率是什么在“扣分”先说一个很多人没想明白的问题:AI率到底在检测什么?它不是在检测你是不是用了某个AI工具,而是在检测文本里那些“所有AI都会这么写”的共性特征。换句话说&#xf…

2026/10/11 14:16:23 阅读更多 →
企业生产级RAG知识库搭建实战:解决大模型幻觉与检索失效问题

企业生产级RAG知识库搭建实战:解决大模型幻觉与检索失效问题

前言在大模型企业落地场景中,RAG检索增强生成是应用最广泛、落地成本最低的核心方案,广泛用于企业内部文档问答、业务知识库、智能客服、资料检索答疑等场景。但绝大多数企业初期落地的基础RAG架构,仅能实现基础Demo演示,一旦接入…

2026/10/11 14:16:23 阅读更多 →
TI 010962 SMU 源测量单元方案:精密测试从选型到实操避坑指南

TI 010962 SMU 源测量单元方案:精密测试从选型到实操避坑指南

1. 从型号到方案:TI 010962 SMU 到底在解决什么问题第一次看到“TI 010962 SMU解决方案”这个标题,很多人会愣一下:这到底是一个芯片型号,还是一套测试方案?我刚开始接触这个方向的时候也有同样的困惑。实际上&#xf…

2026/10/11 14:16:23 阅读更多 →
SVN强制提交日志:VisualSVN Server钩子脚本实战指南

SVN强制提交日志:VisualSVN Server钩子脚本实战指南

确实,不少团队把SVN当作“中转站”:提交记录一句话都不写,或者随手敲个“update”“fix”就完事。等上线出了故障要排查历史版本,看着一排空日志,根本不知道当时改了哪个文件、因为什么改、影响范围在哪——这时候才意…

2026/10/11 14:16:23 阅读更多 →
Python职位推荐系统实战:协同过滤与内容相似度融合

Python职位推荐系统实战:协同过滤与内容相似度融合

简介:这份资源是面向Python初学者与推荐算法入门者的职位推荐系统完整项目资料,围绕基于用户与物品的协同过滤思路,解决招聘场景下职位个性化匹配的实践问题。压缩包共79个文件,约942KB,以47个py源码文件为核心&#x…

2026/10/11 14:15:23 阅读更多 →

日新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →