Vue事件修饰符详解:原理、组合与实战场景
Vue里的事件修饰符大概是模板语法中最让人“又爱又恨”的部分。爱的是一个.stop、一个.prevent写下去事件穿透、表单刷新这些老问题立刻解决恨的是等到链式组合、键盘组合键、.exact这些进阶玩法一起上时很多人就开始懵了甚至压根不知道还有这些修饰符存在。这篇文章不打算复读官方文档而是把高频修饰符的原理、适用场景、踩过的坑逐一说透再配合几个可以直接抄走的实际案例。适合正在学Vue的前端新人也适合写了两三年业务但一直靠复制粘贴写模板的老手——毕竟修饰符这东西会写不难难的是知道什么时候该用、为什么用。1. 先搞清楚事件传播机制修饰符才能看懂1.1 事件在DOM里到底怎么走的要理解事件修饰符绕不开DOM事件的三个阶段捕获、目标、冒泡。打个比方你在小区里喊了一嗓子“谁家狗又跑出来了”这声波先从你家传到小区大门再传到对面楼栋这是捕获阶段最后传到你邻居老王耳朵里他发现是在说自己家狗这是目标阶段然后老王骂骂咧咧的声音又开始一栋楼一栋楼反向传回来这是冒泡阶段。DOM事件也差不多。点击一个嵌套最深的元素事件会先从window一路往下走到目标元素这个过程叫捕获到达目标之后开始向上逐层返回这个过程叫冒泡。Vue里默认监听的就是冒泡阶段所以你在子元素上点击父元素的click往往也会跟着触发这就是最常见的“事件穿透”。需要说清楚的是修饰符是Vue模板编译器提供的语法糖本质上还是在帮我们操作原生事件的stopPropagation、preventDefault这些API。但好处是你不需要在事件处理方法里判断e的来源模板上一行就能精确控制事件的走向业务方法里可以少写一堆防御性代码。1.2 修饰符到底是怎么挂上去的Vue的模板在编译阶段会把click.stop解析成类似这样的逻辑给当前元素绑定click监听器然后在回调里先执行event.stopPropagation()再调用你写的handleClick。编译成render函数后看起来大概是这个意思onClick: (event) { event.stopPropagation(); handleClick(event); }虽然我们平时看不到这层“翻译”过程但理解它非常有用因为修饰符是有顺序的先写谁就先执行谁这一点在后面的链式组合里会坑到不少人。这个角度也解释了为什么修饰符只能用在模板里你在组合式API中手动用addEventListener时自然要自己写原生API修饰符帮不了你。知道这个边界后面排查问题就不容易走偏。2. 高频事件修饰符逐个拆解功能、原理与验证2.1 .stop阻止冒泡先想清楚要不要冒泡.stop可能是业务中用得最多的修饰符。它的作用很简单事件流到此为止不再向上传播。举个真实场景某后台管理系统里有一个卡片列表卡片本身绑定了click用来打开详情弹窗卡片右上角有个“编辑”按钮按钮绑定了click打开编辑面板。如果不做处理点击编辑按钮事件会冒泡到卡片上的click于是编辑面板刚打开详情弹窗也弹出来了两个界面叠在一起用户当场崩溃。代码层面只需要一句话article classcard clickopenDetail(card) button click.stopopenEditor(card)编辑/button /article.stop等价于在openEditor里写event.stopPropagation()但放在模板上可读性更高而且不会污染业务方法。这里有个容易被忽略的细节.stop只管阻止事件继续传播不会阻止默认行为。比如一个a标签绑定了click.stop点击后跳转依然会发生。不想跳转得用.prevent想让跳转和冒泡都消失就得两个一起上。这也是为什么修饰符可以链式写click.stop.prevent。2.2 .prevent拦下浏览器的“默认动作”默认行为这个词听着抽象其实很直观表单里点提交按钮浏览器会把页面刷新一遍a标签点了会跳href在页面上按下空格会滚动右键会弹菜单。这些都不是你写的业务代码干的而是浏览器的内置行为。场景一个搜索页面按下回车触发搜索。如果你把搜索按钮放在form里点击按钮后表单会立刻提交页面带着参数刷新你的接口请求还没发出去就乱了。解决办法很简单form submit.preventonSubmit input typesearch v-modelkeyword / button typesubmit搜索/button /form方法里就可以干干净净只管业务逻辑function onSubmit() { // 发送搜索请求 fetchList(keyword.value); }.prevent对应的是event.preventDefault()但和.stop一样它在阻止默认行为的同时不会管事件传播。所以如果你同时希望事件不要冒泡依然要配合.stop。还有一个要注意的点submit.prevent这类用法整个表单的提交被接管了如果表单里还有别的原生校验逻辑比如required字段这些校验会正常执行但提交动作被拦截。这个行为在不同浏览器上基本一致但校验失败时的提示样式可能会有差异最好统一做自定义校验别指望浏览器原生提示。2.3 .once只触发一次省去手动解绑遇到“首次点击才弹提示”“活动页只允许领取一次奖励”这类需求很多新人会在方法里加一坨判断锁比如用一个hasClicked变量。其实click.once直接帮你搞定了。button click.onceclaimReward领取新人礼包/button对应的原生写法是button.addEventListener(click, handler, { once: true });这里有个很关键的点.once在原生DOM事件和组件自定义事件上行为不一样。在原生DOM事件上它是真正的“只响应一次”但在Vue组件上的自定义事件上它更像是“监听器最多被调用一次”。如果你用some-event.once监听一个自定义组件$emit(someEvent)组件后续再$emit监听器不会再执行但事件本身还是继续发出的其他监听器不受影响。这个差异排查问题时很容易踩坑。2.4 .capture和.self一个管方向一个管对象.capture很少用但理解了事件传播机制你会知道它很有用。默认Vue监听冒泡阶段而.capture改成监听捕获阶段也就是事件从window向目标元素“下潜”的过程。看这个例子div classouter click.capturehandleOuter div classinner clickhandleInner/div /div点击inner时先触发handleOuter再触发handleInner顺序和我们平时期望的冒泡正好相反。捕获模式适合做“全局拦截”类需求比如在容器上统一记录子元素点击的埋点希望在真正的处理器之前先拿到数据。.self则是另一个维度只有当event.target就是当前元素本身时事件才响应。还是嵌套卡片那个例子如果你希望点击卡片空白区域才打开详情点击内部的编辑按钮不要触发卡片事件可以写成div classcard click.selfopenDetail(card) button clickopenEditor(card)编辑/button /div注意区别.stop是让事件不继续传.self是“我只管我自己触发的事件”。点击编辑按钮时事件依然会冒泡到卡片但因为目标不是卡片本身卡片的处理器不会被调用。这个语义更精确能少写一层子元素的stop。2.5 .passive滚动性能的隐形优化器.passive是最容易被人忽略但实际价值很大的修饰符尤其是移动端长列表场景。事件监听器在浏览器里默认是“非被动”的浏览器在处理touchmove这类事件时会先等JavaScript跑完确认你没有调用preventDefault再决定要不要滚动。如果监听器性能差滚动就会明显卡顿。.passive告诉浏览器我不会阻止默认行为你可以直接滚不用等我。在Vue里这样写div classscroll-wrap touchmove.passiveonTouchMove !-- 长列表内容 -- /div一旦加了.passive监听器内部就不能依赖preventDefault来阻止滚动了否则会有告警。所以在滚动容器上如果只是统计滚动位置、更新进度条这类需求.passive非常合适如果要做下拉刷新这类需要拦截滚动并手动控制的行为就不能用.passive得自己接管。两者不能混用。3. 键盘、鼠标与系统修饰符交互细节的进阶玩法3.1 场景化的键盘修饰符键盘修饰符本质上是按键码的语义化封装。像keyup.enter其实等价于判断event.key Enter。Vue给我们内置了一批常用按键比如.enter、.tab、.delete、.esc、.space、.up、.down、.left、.right覆盖了日常大多数场景。我最常用的两个搜索输入框回车触发搜索弹窗按下ESC关闭。input keyup.enterhandleSearch v-modelkeyword / div classmodal-wrapper keyup.esccloseModal tabindex0 !-- 弹窗内容 -- /div这里有个真实教训在弹窗容器上用keyup.esc必须保证焦点在容器内部或其子元素上.esc才会触发。很多人写完之后发现按ESC没反应就是因为焦点跑到容器外面去了。更稳妥的做法是放在document上监听组件卸载时记得清理。如果项目里弹窗组件是统一的封装直接在弹窗组件内部写全局监听会更省心。另一个坑是中文输入法。keyup.enter在部分浏览器和输入法组合下选词确认时的回车上屏事件可能会干扰判断导致搜索框意外触发搜索。稳妥一点的做法是配合compositionstart和compositionend事件来判断输入状态或者干脆在失焦和回车时都做一次过滤这个属于业务层面的防御纯模板修饰符解决不了。3.2 鼠标修饰符与系统修饰符鼠标修饰符有.left、.right、.middle对应左键、右键、中键。最常见的场景是阻止右键菜单弹出自己画一个定制菜单div classcontext-area contextmenu.preventshowCustomMenu !-- 内容区域 -- /div如果你希望只有右键才触发某个行为不干扰左键可以配合.rightdiv classtable-row click.right.prevent.stopopenRowMenu(row)/div系统修饰符是另一个层次.ctrl、.alt、.shift、.meta。它们描述的不是事件本身而是事件发生时的按键状态。比如CtrlS保存草稿div keydown.ctrl.s.preventsaveDraft.../div注意.ctrl.s这类组合是系统修饰符普通按键的写法keydown.ctrl.s会拦截CtrlS的浏览器默认行为保存页面所以.prevent几乎必然要带上。.exact修饰符是很多人没听过但非常实用的它要求精确匹配按键组合。举个例子click.ctrl表示只要按着Ctrl点击就触发此时如果同时按了Alt或Shift它依然会触发但click.ctrl.exact要求只按Ctrl才触发多按任何一个键都不行。反过来click.exact表示只有不按任何系统修饰键时点击才触发。这个在快捷键系统里非常有用能避免组合键之间的误触发。4. 修饰符组合规则与实战案例拆解4.1 链式修饰符的顺序潜规则链式写法在Vue里是常用操作但顺序问题很多人没细想过。Vue官方文档里专门有一条提示使用修饰符时顺序很重要因为代码会按照同样的顺序执行。最经典的对比是a click.prevent.selfhandleAA/a a click.self.preventhandleBB/a第一个会先执行preventDefault再判断目标是否是自己结果是所有点击都被阻止了默认行为但只有点击到元素本身时才执行方法第二个先判断目标再执行preventDefault结果是只有点击元素本身时才既阻止默认行为又执行方法点击子元素则什么都不发生。这个差异在嵌套结构里非常容易踩坑。我现在写的时候有个习惯如果修饰符之间有优先级关系会把“更前置、更全局”的修饰符放在前面同时尽量在注释里说明意图。模板比以前干净但坑其实更隐蔽所以顺序需要稳。4.2 修饰符在自定义组件上的正确打开方式事件修饰符能不能用在组件上这个要分原生事件和自定义事件来看。原生事件比如你在自定义组件上想拦截click冒泡直接click.stop写在组件标签上是有效的因为Vue会把未知的attrs传给组件的根元素click监听照样会被挂在根节点上。但组件如果有多个根节点这种写法可能会失效并触发告警这是Vue 3里常见的坑。自定义事件父组件监听子组件通过emits声明的自定义事件时.once、.prevent这些修饰符并不适用因为子组件emit是一个纯粹的通知行为和DOM事件机制不一样。.once在自定义事件上还保留“最多执行一次”的语义但.stop这种完全没有意义因为自定义事件没有“冒泡”的说法。Vue 2时代还有click.native用来监听组件根元素的原生事件Vue 3已经移除这个修饰符了。现在要监听自定义组件根元素的原生事件可以通过判断emits和inheritAttrs来实现或者在子组件内部自己绑定。这个迁移点从Vue 2项目升级到Vue 3的团队要格外注意。4.3 案例一个真正可控的防重复提交按钮讲完原理来一个能直接落地的组合案例。业务场景某个活动报名页提交按钮点击后要拉接口如果用户手速快连续点了好几下接口会被打爆还可能出现重复报名记录。传统的做法是在方法里加一个isSubmitting锁const isSubmitting ref(false); function handleSubmit() { if (isSubmitting.value) return; isSubmitting.value true; // 提交逻辑 }锁本身没有错但如果你用click.oncebutton click.oncehandleSubmit立即报名/button点击一次之后监听器自动失效除非刷新页面否则这个按钮再也不会执行handleSubmit相当于从源头上杜绝了重复触发。这个方法对“一次机会”类操作特别契合比如领取优惠券、确认订单。但要注意.once只防护“同一时刻的连续点击”如果接口失败需要重新提交.once会直接失效。所以“接口失败后允许重试”的业务场景.once不合适得用状态锁按钮禁用。我一般在需求评审时就明确这类按钮是一次性还是可重试决定了用.once还是状态锁。4.4 案例长列表滚动的性能优化与节流移动端长列表最容易出现滚动卡顿。除了数据量本身的原因事件监听器的性能也很关键。假设需求是滚动时记录当前位置更新进度条div classlist scroll.passiveonScroll div v-foritem in list :keyitem.id classlist-item{{ item.name }}/div /div方法里做节流import { throttle } from lodash-es; const onScroll throttle((e) { progress.value e.target.scrollTop / (e.target.scrollHeight - e.target.clientHeight); }, 100);scroll在连续触发时频率很高节流函数能有效减少不必要的计算。.passive则让浏览器不需要等待JavaScript判断是否要preventDefault直接开始滚动从事件源头提升流畅度。这里有个细节scroll.passive和touchmove.passive的使用场景不完全一样。桌面端鼠标滚轮的滚动优化用scroll事件的.passive收益不一定明显因为scroll事件本身就是异步的但移动端touchmove的.passive收益非常大。很多性能分析报告里提到“passive event listener”优化的就是这种场景。5. 常见问题与排查技巧实录5.1 问题速查表我把实际开发里高频遇到的修饰符问题整理了一张表现象原因处理建议.passive和.prevent同时使用有告警两者语义冲突浏览器忽略.prevent选择其中一种不要混用keyup.enter不触发焦点不在输入框或者中文输入法组词阶段回车检查焦点必要时配合composition事件判断组件标签上click.stop不生效组件多根节点事件监听没有挂到预期元素包裹一层单根节点或在子组件内部处理click.self下子元素点击仍触发目标元素判断与预期不符确认事件是冒泡还是捕获阶段触发click.prevent.stop和click.stop.prevent结果不同链式修饰符按书写顺序执行明确执行顺序后再组合自定义事件上使用.prevent自定义事件与DOM事件机制不同用.once或业务逻辑控制.once在组件自定义事件上表现不同监听器最多调用一次但事件仍继续发出分清场景再选用Vue 2的.native在Vue 3中失效Vue 3移除了.native改用emits声明和根元素监听方式这些坑很多我自己都踩过尤其是前三个排查的时候最容易绕弯子。5.2 踩坑经验与排查思路排查修饰符问题最怕在复杂模板里猜。我的习惯是先看控制台告警比如.passive和.prevent同时使用会有明确的警告输出然后是Vue DevTools里的事件日志它能显示组件树上的事件绑定情况最后才去看模板本身。如果实在查不出原因我会用一个最小复现模板去隔离变量一个空Vue组件只保留一段事件绑定的代码在页面单独跑。这样能很快判断问题出在修饰符本身还是业务逻辑的某个地方干扰了事件。另外分享一个小技巧如果某个click在本地复现不了先在浏览器原生的addEventListener上试一遍同样逻辑。若原生都不触发那问题根本不在Vue层多半是元素被遮挡、被移除了或者事件被提前消费了。很多修饰符问题排查到最后发现是CSS里的pointer-events或者z-index在捣鬼。我个人在实际项目里的体会是事件修饰符像是一套“事件处理的声明式语法”写得好模板就像是在说人话一眼就能看出点击这个按钮会发生什么写坏了调试成本远高于你省下的那几行代码。我见过不少项目里把.stop和.prevent混着乱用最后不得不全局搜索click.stop.prevent逐个试这种时候真的会很怀念约束严格的代码评审。所以最后分享一个小建议在团队里约定修饰符的使用规范比如不要滥用.stop能用.self精确命中就不多写一层stop凡是出现链式修饰符后面必须跟注释。这套约定我们实践下来效果不错线上事件类Bug少了很多。如果你刚接触Vue先把.stop、.prevent、.once这三个用熟再慢慢扩展到键盘和系统修饰符。工具永远是越练越顺手的事件修饰符也一样。

相关新闻

SQLITE-WEB 远程访问完全指南:监听、防火墙、SSH 转发与安全加固

SQLITE-WEB 远程访问完全指南:监听、防火墙、SSH 转发与安全加固

如果你手上有几个 SQLite 数据库文件,散落在服务器或自己的电脑里,想用浏览器直接看表、跑 SQL、导出 CSV,SQLITE-WEB 是我用得最顺手的工具之一。它本质上是一个用 Go 写的轻量 Web 服务,把一个 SQLite 文件暴露成可交互的管理页…

2026/10/16 4:06:13 阅读更多 →
MATLAB xcorr 的 C 语言实现:直接法与 FFT 加速及归一化选项

MATLAB xcorr 的 C 语言实现:直接法与 FFT 加速及归一化选项

简介:这份资源面向信号处理学习者与嵌入式开发人员,提供MATLAB中xcorr函数在C语言环境下的完整实现方案,解决跨平台移植与高性能计算场景下互相关计算的需求。包内共2个文件,包含1个c源文件与1个h头文件,压缩包约2KB&a…

2026/10/16 4:06:13 阅读更多 →
柯西分布量子粒子群优化CQPSO在LTE基站选址覆盖优化中的应用

柯西分布量子粒子群优化CQPSO在LTE基站选址覆盖优化中的应用

1. 从现场问题说起:基站覆盖率为什么不是一个“多建站”就能解决的问题我在做LTE网络规划优化的时候,最常听到的一句话就是“覆盖不行就加站”。这个说法听起来简单,但实际做起来完全不是这么回事。某片区基站数量并不算少,可是因…

2026/10/16 4:06:13 阅读更多 →

最新新闻

Python控制硬件:Arduino与树莓派实战对比与协同架构

Python控制硬件:Arduino与树莓派实战对比与协同架构

聊到用Python控制硬件,大部分教程会把Arduino和树莓派放在同一个标题下讲,好像这俩就是同一个东西的两种形态。等我把两种方案都跑进真实项目里,才发现开发体验完全不一样:Arduino这条路,核心是和串口协议斗智斗勇&…

2026/10/16 4:48:25 阅读更多 →
eSIM开户安全基石:二要素认证的技术拆解与工程实践

eSIM开户安全基石:二要素认证的技术拆解与工程实践

eSIM这个概念聊了很多年,真正大规模落地也就是近几年的事。我最早接触eSIM开户相关的项目,是在给某运营商做线上开户支撑系统的时候。那时候团队讨论最多的还是Profile怎么下发、兼容性怎么处理,等到线上开户量真正涨起来,大家才猛…

2026/10/16 4:48:25 阅读更多 →
eSIM开户的二要素认证:原理、落地与避坑指南

eSIM开户的二要素认证:原理、落地与避坑指南

eSIM开户已经不是什么新鲜事,但很多人不知道,真正决定开户能不能顺利完成的,不是手机型号,也不是网络条件,而是二要素认证。我在处理线上开户反馈时,经常遇到用户卡在“身份核验”这一步,要么证…

2026/10/16 4:48:25 阅读更多 →
KV Cache 显存优化实战:长上下文推理性能瓶颈与调优策略

KV Cache 显存优化实战:长上下文推理性能瓶颈与调优策略

1. 从一次对话卡顿说起:KV Cache 到底在解决什么问题如果你用过任何基于 Transformer 架构的对话模型,大概率遇到过这样一种体验:刚开始聊的时候,回复速度飞快,字是一个一个往外蹦的;聊到几十轮之后&#x…

2026/10/16 4:48:25 阅读更多 →
JavaScript数组reduce实战:核心原理、业务场景与边界问题

JavaScript数组reduce实战:核心原理、业务场景与边界问题

提起数组的reduce方法,大多数前端开发者的状态是:面试前背过“累加器”“归并”这些概念,真到项目里却很少主动用。我观察过不少团队的代码评审,reduce常常被两派人争论:一派觉得它晦涩难懂,看到就想改成fo…

2026/10/16 4:48:25 阅读更多 →
光储充换电站分时电价双层优化模型及Matlab实现

光储充换电站分时电价双层优化模型及Matlab实现

光储充换电站和分时电价互动这两件事,放在一起研究的论文和代码我见过不少,但真正能把“用户充电负荷”这个变量建模得当、又能在Matlab里跑通寻优的,确实不算多。这个标题对应的方向,简单说就是:站在运营商的视角&…

2026/10/16 4:47:24 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

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

2026/10/16 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 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/15 0:14:36 阅读更多 →
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/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练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/15 9:49:14 阅读更多 →