lightweight-charts Brushable Area Series 插件实战:brushRanges 选区样式、交互原语与 Canvas 渲染原理
前端图表库金融科技数据可视化【免费下载链接】lightweight-chartsPerformant financial charts built with HTML5 canvas项目地址https://gitcode.com/gh_mirrors/li/lightweight-charts点击查看免费下载本文围绕 lightweight-charts 官方发布的tradingview/lwc-plugin-brushable-area-series插件展开它允许在同一张区域图area series上通过brushRanges将不同数据段渲染成各自独立的线条与填充样式再配合可选的BrushableAreaInteraction交互原语实现鼠标/触控拖拽选区。读完本文你将掌握该插件的安装方式、完整选项表、刷选交互接入方法以及其分段绘制、渐变填充与显式空白whitespace处理的底层实现原理。该插件已从plugin-examples示例目录毕业为独立发布包其源码、演示页与目录页预览均位于 packages/lwc-plugin-brushable-area-series旧的示例目录 plugin-examples/src/plugins/brushable-area-series/README.md 保留了一个指向/plugin-demos/brushable-area-series/的重定向 stub保证旧画廊链接继续可用。插件定位能给数据分段配色的区域系列这是一个标准的 lightweight-charts自定义系列custom series数据仍是{ time, value }的普通区域图但你可以为整条系列设置一套基础样式base style并叠加任意数量的brush range刷选区间——每个区间是一段数据点拥有自己独立的线条色与填充色。值得强调的是系列本身只负责画样式。把鼠标拖拽变成选区需要额外接入可选的BrushableAreaInteraction系列原语series primitive或者由你自己编写指针处理逻辑用户在图上一拖被拖过的区间的brushRanges就被设置上区间之外保持基础样式。只要给outsideStyle一个半透明样式就能得到经典的选区鲜艳、其余淡化效果。典型应用场景包括迷你走势图sparkline或总览图上的区间选择、对一段时期如某个交易时段、事件窗口、回测样本做高亮、以及在同一系列内部视觉化对比不同区段。安装npm 与 CDN 两种方式插件要求项目中使用lightweight-charts^5.0.0peer 依赖声明见 package.json。npm 安装npm install tradingview/lwc-plugin-brushable-area-series随后导入插件并添加到图表import { createChart } from lightweight-charts; import { createBrushableAreaSeries } from tradingview/lwc-plugin-brushable-area-series; const chart createChart(document.getElementById(container)); const series createBrushableAreaSeries(chart, { lineColor: rgb(41, 98, 255), topColor: rgba(41, 98, 255, 0.4), bottomColor: rgba(41, 98, 255, 0), priceLineVisible: false, }); series.setData(data); // [{ time, value }, ...]CDN 引入插件以 ES modules 发布。通过 import map 将库与插件映射到各自的 CDN 构建产物script typeimportmap { imports: { lightweight-charts: https://unpkg.com/lightweight-charts^5/dist/lightweight-charts.standalone.production.mjs, tradingview/lwc-plugin-brushable-area-series: https://unpkg.com/tradingview/lwc-plugin-brushable-area-series/dist/brushable-area-series.standalone.js } } /script之后就能像在打包器环境下一样按包名导入script typemodule import { createChart } from lightweight-charts; import { createBrushableAreaSeries } from tradingview/lwc-plugin-brushable-area-series; const chart createChart(document.getElementById(container)); const series createBrushableAreaSeries(chart, { lineColor: rgb(41, 98, 255), topColor: rgba(41, 98, 255, 0.4), bottomColor: rgba(41, 98, 255, 0), priceLineVisible: false, }); series.setData(data); // [{ time, value }, ...] /script快速上手设置 brushRanges 与 outsideStyle通过createBrushableAreaSeries添加自定义系列并写入单值数据后只要选区变化随时通过applyOptions更新brushRangesimport { createChart } from lightweight-charts; import { createBrushableAreaSeries } from tradingview/lwc-plugin-brushable-area-series; const chart createChart(document.getElementById(container)); const series createBrushableAreaSeries(chart, { lineColor: rgb(41, 98, 255), topColor: rgba(41, 98, 255, 0.4), bottomColor: rgba(41, 98, 255, 0), priceLineVisible: false, }); series.setData(data); // [{ time, value }, ...] // 将 40–80 号点位高亮为绿色其余淡化。 series.applyOptions({ brushRanges: [ { range: { from: 40, to: 80 }, style: { lineColor: #089981, topColor: rgba(8, 153, 129, 0.4), bottomColor: rgba(8, 153, 129, 0), lineWidth: 3, }, }, ], outsideStyle: { lineColor: rgba(41, 98, 255, 0.2), topColor: rgba(41, 98, 255, 0.05), }, }); // 清除选区整条系列回到基础样式。 series.applyOptions({ brushRanges: [] });两条关键的语义约定区间的style与系列级outsideStyle都是部分样式partial凡是被省略的属性都会回退到系列的基础样式。这一基础合并逻辑由 style.ts 中的mergeStyle实现对lineColor / topColor / bottomColor / lineWidth / lineStyle五个属性逐一做?? base回退。brushRanges使用的是时间刻度的逻辑索引logical indices——即图表自身坐标轴上、被所有系列共享的位置编号而不是时间值也不是该系列自己数据数组的下标。要把指针位置换算成逻辑索引用chart.timeScale().coordinateToLogical(x)其中x是指针在绘图区内的水平位置。每个数据点是{ time, value }没有value的点会被当作空白whitespace处理线条在缺口处断开而不是跨过去桥接。源码视角样式如何被解析与合并style.ts 的createStyleResolver为每个逻辑索引解析出最终样式其规则与单元测试 tests/unit/style.spec.ts 逐一对应无 brush range 时所有点返回基础样式outside等于 base区间命中from含、to不含index from index to测试用例明确断言resolve(2)与resolve(3)命中、resolve(1)与resolve(4)不命中区间重叠时后写者胜last wins解析器从数组末尾向前扫描后设置的区间覆盖它拖过的旧区间新选区覆盖旧高亮的行为符合用户直觉outsideStyle 仅在至少设置了一个区间时才生效同一来源样式的点共享同一个样式对象渲染器正是依赖这一点才能把连续同色的点合并成一条路径一次性绘制避免同色段之间出现接缝seam。BrushableAreaInteraction把拖拽变成选区BrushableAreaInteraction是一个可选的系列原语把鼠标拖拽、单指拖拽或双指手势统一归一化为 brush range这样每个应用就不必重复编写指针处理逻辑import { BrushableAreaInteraction, } from tradingview/lwc-plugin-brushable-area-series; const brush new BrushableAreaInteraction({ style: { lineColor: #089981, topColor: rgba(8, 153, 129, 0.4) }, outsideStyle: { lineColor: rgba(41, 98, 255, 0.2) }, }); series.attachPrimitive(brush); brush.activeRange().subscribe(range { // null once the selection is cleared by a click without a drag if (range ! null) { console.log(range.from, range.to, range.fromTime, range.toTime); } });交互选项表交互选项类型默认值说明stylePartialstyle绿色应用于被刷选区间的样式。outsideStylePartialstyle淡蓝色应用于刷选区间之外的样式。applyToSeriesbooleantrue用户拖拽时实时写入系列的brushRanges。关闭后仅通过activeRange事件接收选区。minimumRangeWidthnumber1以逻辑索引计的最小拖拽宽度小于该宽度的拖动不算一个区间。这些默认值以defaultInteractionOptions导出。activeRange()报告的区间带有from/to逻辑索引以及fromTime/toTime两端数据点的时间该处没有数据点时为null。brush.clear()清除选区brush.range()返回当前选区。由于图表自身的拖拽手势与刷选冲突使用该原语的图表通常要同时关闭图表自身的平移与缩放const chart createChart(container, { handleScroll: false, handleScale: false, });实现细节鼠标与触控的归一化从源码结构看交互层由两部分组成multi-touch.ts 的MultiTouchChartEvents监听图表元素上的mousedown/mousemove/mouseup/mouseleave与touchstart/touchmove/touchend/touchcancel把从 A 拖到 B和两根手指分别在 A 与 B归一化成同一组TouchPoint每个点含水平坐标与所在逻辑索引。单指拖动时会把落指位置与当前位置组成区间端点。_point内部正是通过coordinateToLogical(x)完成像素到逻辑索引的换算。interaction.ts 的_onMove取第一与最后一个点计算from/to宽度不足minimumRangeWidth时直接忽略_setRange在applyToSeries为真时把{ brushRanges: [{ range, style }], outsideStyle }写入系列并触发activeRange。值得注意的交互约定拖拽之外的点击会清除选区_onEnd在未形成区间时_setRange(null)于是同一手势既能画选区也能删选区。Options 完整参考基础样式与区域填充除标准系列选项priceLineVisible、lastValueVisible、priceFormat、autoscaleInfoProvider等之外该插件还提供以下选项默认值见 options.ts选项类型默认值说明lineColorstringrgb(40,98,255)基础线条颜色用于 brush range 之外的区域。topColorstringrgba(40,98,255, 0.4)线条处渐变顶端的基础填充色。bottomColorstringrgba(40,98,255, 0)基准价处渐变底端的基础填充色。lineWidth1 \| 2 \| 3 \| 42基础线宽单位为 CSS 像素。lineStyleLineStyleLineStyle.Solid线条的基础虚线样式。lineVisiblebooleantrue是否绘制线条本身设为false只保留填充。lineTypeLineTypeLineType.Simple相邻两点间线条形状直线、阶梯或曲线填充跟随同一形状。relativeGradientbooleanfalse将填充渐变远端锚定到视野内最外侧数据点而非像内置AreaSeries那样锚定到面板边缘。invertFilledAreabooleanfalse改为向上填充到面板顶部而非向下填充到basePrice。basePricenumber0面积向下填充所到达的价格。brushRanges{ range: { from: number; to: number }; style: Partialstyle }[][]以逻辑索引表示、按各自样式渲染的区间集合。from含、to不含传空数组即清除。outsideStylePartialstyle—所有 brush range 之外数据点的样式仅在至少设置一个区间时生效。其中style即{ lineColor, topColor, bottomColor, lineWidth, lineStyle }五个属性与基础样式完全一致且每个属性都可选。渲染原理分段路径、渐变与越界处理渲染由 renderer.ts 中的BrushableAreaSeriesRenderer完成其核心逻辑值得展开分段与右点定风格。绘制前先用extendRange把可见范围各向外扩一根 bar让线条/填充穿出面板边缘而不是在最后一个可见点处戛然而止平移图表时视觉上更自然。随后把每个点解析出样式凡是共享同一样式对象的连续点就合并为一条路径一次性描边/填充因此同色段内不会出现接缝每段路径的样式由右端点决定。价格超出当前价格刻度范围的点以及数据缺口都会断开线条而不是画到非法坐标priceToCoordinate返回null即 break。填充渐变。填充是垂直渐变bottomColor位于basePricetopColor位于填充延伸方向的面板边缘开启relativeGradient时为视野内最外侧数据点。当basePrice落在可见价格区间之外时填充直接延伸到面板边缘basePriceY被钳制到0..paneHeight。invertFilledArea为真时填充向上到面板顶部。CURVE_TENSION 6的三次贝塞尔控制点构造与图表内置曲线线条相同见 renderer.ts。单点也可见。当可见范围内只有一个数据点时仍会绘制一个等于线宽的圆点标记保证缩放/平移到极端位置时画面不丢失信息。虚线接缝处理。描边时实线Solid用圆头线帽来弥合两段不同样式路径的交界虚线则保留平头线帽以保证虚线段长度正确renderer.ts。这些规则与 graphics 测试一一对应例如 tests/graphics/brush-range.js 验证点位 30..49 保持鲜艳、其余淡化的渲染结果overlapping-ranges.js、relative-gradient.js、base-price.js、line-hidden.js、line-type.js、whitespace-gap.js等分别覆盖重叠区间、相对渐变、基准价、隐藏线条、线条类型与空白缺口。显式空白Explicit Whitespace与时间刻度合并这是该插件区别于普通自定义系列的一个重要特性请优先使用createBrushableAreaSeries工厂它通过 lwc-toolkit 的 createWhitespaceSeries 保留setData/update含历史修正传入的空白数据因此只有显式空白才断开线条与填充其他系列贡献的时间戳不会打断本系列的区域。底层BrushableAreaSeries视图类仍保留导出可用于chart.addCustomSeries或组合进其他系列但它没有工厂提供的 gap 判定会连续绘制——宿主并不会把空白信息提供给自定义渲染器。在时间刻度合并conflation下面积按多个 bar 的桶bucket绘制窄于一个桶的空白段在该 bar 间距上无法解析会被吸收进桶内而不是逐 bar 断开缩放越过合并阈值后缺口会重新显现。这一行为在 renderer.ts 中通过getConflationFactor(data)计算最小缺口宽度实现。另外工厂返回的是保留插件自身数据与选项类型的OptionsAwareSeries其applyOptions会在价格类选项变化时重建已存储的绘图值同时保留原始数据、空白与自定义字段setData/update内部按时间键排序并缓存流式更新走二分查找见 options-aware-series.ts。实战注意事项汇总区间内点以该区间样式绘制区间重叠时最后一个匹配区间胜出因此新选区会覆盖其拖过的旧选区。每个绘制的线段采用其右端点样式连续同色点合并为一条路径同色段内无缝。填充是自bottomColorbasePrice处到topColor填充延伸方向的面板边缘或relativeGradient下的最外侧可见点的垂直渐变basePrice超出可见价格区间时填充直达面板边缘。线条与填充会在可见范围两侧各多画一根 bar平移图表时以穿出面板替代停在最后一个可见点。价格超出当前价格刻度范围的点、以及数据缺口会断开线条而非画到非法坐标。示例图表均关闭了滚动与缩放handleScroll、handleScale把拖拽手势让给刷选你需要决定自己的图表应由哪个手势主导参考 example.ts。示例与测试从 demo 到目录预览插件的两个页面都构建自包内源码完整演示 src/example/index.html含 brush style 切换、line style 切换、base price 滑块等控件与目录预览 src/example/preview.html。运行pnpm plugins:build-demos会把两者构建进文档站点分别位于/plugin-demos/brushable-area-series/与/plugin-previews/brushable-area-series/。演示中值得借鉴的写法包括先添加一条覆盖全区间、半透明的普通LineSeries作为参考线再让可刷选系列晚 40 根 bar 开始——从而验证brush range 是时间刻度的逻辑索引即使可刷选系列不是第一个系列也依然正确数据中部第 110..124 号点只给time不给value用于演示空白断线效果example.ts。测试方面tests/unit/style.spec.ts 用 7 个用例覆盖样式解析的全部规则无区间、完整区间样式、部分样式回退、from/to开闭、重叠后写者胜、outsideStyle生效条件、同源样式共享对象是理解该插件行为语义最直接的入口graphics 测试则从渲染像素层面验证了区间配色、渐变、线型、空白缺口等视觉行为可作为回归基线。赞分享前端图表库金融科技数据可视化【免费下载链接】lightweight-chartsPerformant financial charts built with HTML5 canvas项目地址https://gitcode.com/gh_mirrors/li/lightweight-charts点击查看免费下载相关推荐lightweight-charts Brushable Area Series 插件实战用画刷范围高亮与选择任意数据区间lightweight charts Brushable Area Series 插件实战用画刷范围高亮与选择任意数据区间 导读 本文介绍 lightweig前端图表库金融科技数据可视化Lightweight Charts™ 可刷选区域序列Brushable Area Series插件完全指南1.0.0 特性、选项体系与源码实现剖析Lightweight Charts™ 可刷选区域序列Brushable Area Series插件完全指南1.0.0 特性、选项体系与源码实现剖析 Li前端图表库金融科技数据可视化Lightweight Charts HLC Area Series 插件实战指南high-low-close 区间面积图的安装、配置与源码原理Lightweight Charts HLC Area Series 插件实战指南high low close 区间面积图的安装、配置与源码原理 本指南围绕当前端图表库金融科技数据可视化创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

MySQL时间时区修改详解:从time_zone到default-time-zone的完整排查指南

MySQL时间时区修改详解:从time_zone到default-time-zone的完整排查指南

接手过数据库的人,应该都体会过“时间差8小时”的焦虑。某次凌晨线上告警,业务方截图发过来:对账报表里所有订单时间都比实际晚了8个小时,排查了一圈,最后定位到 MySQL 的时区设置上。这种事几乎每个用 MySQL 做业务的…

2026/10/11 20:42:28 阅读更多 →
空天通信网络关键技术:链路预算、星间路由与协议栈裁剪实战

空天通信网络关键技术:链路预算、星间路由与协议栈裁剪实战

简介:这份文档资料面向通信工程、卫星互联网与空天信息网络方向的研究人员、研究生及技术从业者,系统梳理空天通信网络的关键技术体系,帮助读者快速建立从架构到物理层的整体认知。资源为单个docx文档,压缩包约209KB,内…

2026/10/11 20:42:28 阅读更多 →
新增数据字典完整落地:表结构、缓存策略与编码规范

新增数据字典完整落地:表结构、缓存策略与编码规范

1. 这次改动到底在改什么在后台管理系统里,“新增数据字典”可能是出现频率最高的需求之一。很多刚入行的开发看到这个需求,觉得不就是建一张表、加几条记录吗?实际上数据字典承担着整个系统的基础数据标准化工作,它的设计质量直接…

2026/10/11 20:42:28 阅读更多 →

最新新闻

API迁移建议生成中的上下文锚定:从大模型幻觉到可靠实践

API迁移建议生成中的上下文锚定:从大模型幻觉到可靠实践

我在接手模拟项目X的API迁移工作时,最头疼的不是某个接口怎么改,而是几百个存量调用点一起改。打开新版文档对照旧代码逐行看,眼睛都快看花了,团队里也总有人问"这个参数到底对应新接口的哪个字段"。后来我把目光转向了…

2026/10/11 22:18:03 阅读更多 →
安全狗安装配置实战:服务器主机安全防护与暴力破解拦截

安全狗安装配置实战:服务器主机安全防护与暴力破解拦截

前阵子有朋友的服务器被挂上了挖矿程序,CPU直接飙到100%,一查SSH日志几千条暴力破解记录。折腾了一晚上清理完,第二天又被打进来,最后给他装了个安全狗,才算安稳了几天。这种经历做运维的应该不陌生——明文端口暴露在…

2026/10/11 22:18:03 阅读更多 →
达梦DSC共享存储集群搭建指南:从架构选型到故障演练

达梦DSC共享存储集群搭建指南:从架构选型到故障演练

1. 先弄清DSC的定位:共享存储和主备、读写分离有什么不同1.1 为什么最终选了DSC双节点,而不是继续用数据守护主备在动手搭这套达梦数据库共享存储集群之前,我先把需求捋了一遍:业务侧要求两个数据库节点都能对外提供读写服务&…

2026/10/11 22:18:03 阅读更多 →
基于PyQt5与α-β剪枝的五子棋博弈搜索实战

基于PyQt5与α-β剪枝的五子棋博弈搜索实战

简介:这份资源是面向计算机相关专业学生与开发者的毕业设计级五子棋AI项目,采用Python与PyQt5构建图形界面,核心实现人机博弈,并引入深度优先搜索与α-β剪枝算法提升AI决策效率,适合作为人工智能、游戏开发方向的课程…

2026/10/11 22:18:03 阅读更多 →
微信聊天记录结构化导出:从SQLite提取到HTML/Word/CSV三格式交付

微信聊天记录结构化导出:从SQLite提取到HTML/Word/CSV三格式交付

简介:这是一套面向微信用户与Python开发者的聊天记录分析工具集,解决个人聊天数据长期保存、多格式导出及年度行为洞察的实际需求,适用于数字存档爱好者、数据分析初学者及轻量级微信应用开发者。资源包共238个文件,以94个Python脚…

2026/10/11 22:18:03 阅读更多 →
YOLO11电缆损伤检测实战:环境配置、训练调参与推理落地

YOLO11电缆损伤检测实战:环境配置、训练调参与推理落地

简介:面向电力设施维护与安全检查场景,这份ultralytics-yolo11电缆损伤识别资源包提供了从数据集到训练模型的一站式方案。包内包含1318张已标注图像,分别提供YOLO格式txt标签与VOC格式xml标签,并已划分好train/val/test子集&…

2026/10/11 22:17:02 阅读更多 →

日新闻

流感时间序列预测实战: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/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练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/11 14:36:54 阅读更多 →