尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
uniapp自定义底部导航栏:从方案选型到根治切换闪烁
上周接了个商城改版的活儿产品经理一口气提了好几个底部导航的“野需求”中间要凸起一个发布按钮购物车要挂动态角标不同登录状态看到的tab数量还不一样。在uniapp里折腾半天发现原生tabBar根本框不住这些东西最后只能走自定义底部导航栏这条路。导航栏做完还没松口气又被切换选项卡时的页面闪烁问题折磨得够呛——切过去白屏一下要么内容先空后满跳一下怎么调都觉得糙。这篇文章把这次从方案选型到完整实现、再到闪烁问题根因排查的过程写成一份能落地的笔记给同样被这两个问题卡住的朋友做个参考。1. 原生tabBar的限制什么场景让你不得不自己动手1.1 不是每个项目都需要自定义导航栏先把丑话说在前面uniapp原生tabBar的稳定性是经过大量线上项目验证的如果需求只是“四五个tab、文字加图标、选中换颜色”那就老老实实用原生配置一分钟就能在pages.json里搞定切换页面也顺滑没必要自己造轮子。自定义导航栏看着灵活但其实意味着你需要自己处理页面切换、选中态同步、安全区适配、状态保留这一整套事情。后端接口只要你返回一个数量前端就得想好怎么把这个数量动态塞进tab上的角标里。这些都是成本。所以判断标准很简单原生tabBar能不能满足你的全部交互需求。能满足别折腾不能满足再往下看。1.2 原生方案兜不住的几类需求结合我这次接到的需求以及过往项目里常见的定制点下面这几类场景基本都是原生tabBar干不动的中间凸起按钮比如淘宝、闲鱼那种中间大按钮原生tabBar的图标和文字布局完全固定插不进去一个凸出的独立元素。动态角标和红点原生tabBar的iconPath是写死的图片路径虽然小程序端有wx.setTabBarBadge这类API但uniapp多端编译下H5和App端的表现并不统一而且角标样式也没法自定义。按角色/状态显示不同tab比如未登录时显示4个tab登录后变成5个原生配置只能写死一套list。复杂交互动效点击缩放、渐变过渡、选中图标切换动画原生tabBar统统不支持。点击拦截和埋点想在tab点击时做登录校验、埋点统计原生tabBar只能通过onTabItemTap页面生命周期监听拦截能力很弱。只要沾上其中一条代码里就会开始出现大量“绕过原生tabBar”的hack与其在这里补丁叠补丁不如一开始就走自定义。1.3 官方custom模式的真实处境你可能会说uniapp在pages.json里不是支持tabBar.custom吗没错官方确实提供了自定义tabBar的能力我在项目里也实测过但这个模式目前在小程序端相对成熟H5和App端的支持情况和渲染层级限制都不太一样而且它本质上仍然是“原生页面栈自定义遮罩层”的架构。什么意思呢就是说你虽然能自己画tabBar的外观但页面切换还是走原生tabBar那套机制用的还是uni.switchTabtabBar组件的渲染层级也受原生限制动画和复杂样式经常施展不开。另外官方custom模式要求tabBar组件里的内容必须用cover-view承载这是因为原生tabBar渲染在原生层普通view会被原生tabBar盖住。这也意味着很多CSS能力都要打个折扣。2. 技术路线选型单页多视图与多页面方案的取舍2.1 三条路线的横向对比在动手写代码之前我先花了一天时间把方案理清楚。市面上常见的自定义导航栏实现方式大概有三条我做了个对比方便你按项目情况对号入座方案实现成本切换闪烁程度页面状态保留分享定位内存占用原生tabBar低低但onShow重复触发需优化页面常驻可保留原生支持中官方custom模式中中受渲染时序影响页面常驻可保留原生支持中自绘组件多页面中高reLaunch会重建页面弱状态需要跨页传递可传参处理低自绘组件单页多视图较高极低页面永不被销毁强状态天然保留需要手动拼URL参数较高这里最关键的变量其实是页面切换方式。在uniapp里如果不配置原生tabBar一个页面就无法成为真正的“tab页面”也就不能用uni.switchTab这种保留页面实例的API。很多人的第一反应是用uni.reLaunch或uni.redirectTo跳转这两个API都会销毁当前页面并重新创建目标页面于是每次切tab都相当于从零渲染一个新页面——闪烁自然就来了。2.2 我为什么最终选了“单页多视图”既然切tab的闪烁根源在于页面重建那最彻底的解法就是让页面压根不重建。这次我采用的方案是在一个宿主页面里把四个tab对应的内容拆成四个子组件同一时间只显示其中一个用v-show控制显隐。四个子组件都常驻在页面里切tab只是切换v-show的状态没有页面销毁没有重新渲染白色闪烁的问题从根上就没了。可能有朋友会问那为什么不直接用v-ifv-if是真正的销毁和重建每次切过去都会重新走一遍组件的生命周期、重新拉数据画面依然会闪。v-show只是改CSS的display组件状态和DOM都还在所以切换几乎是即时的。2.3 这条路线的副作用和使用前提“单页多视图”听着很美好但它的前提和代价你也得心里有数。一个明显的副作用是四个子组件同时挂在同一个页面里首屏启动时会一次性创建四个组件如果某个tab里放了地图、长列表这类重型内容会拖慢宿主页面的首次渲染。我的解决思路是“懒挂载”后面第四章会单独讲。另一个代价是所有tab内容共享一个URL分享路径只能指向宿主页面没办法直接定位到某个子tab。如果你的产品对分享链路要求很高比如用户要把“购物车页面”直接分享给对方这条路就得慎重。所以这个方案的适用场景是tab页面不算特别重、对分享定位要求不高、但对切换流畅度要求极高的项目。如果你反过来宁可要原生页面栈的分享能力和稳定性愿意接受onShow导致的轻微闪烁那可以走“官方custom模式页面常驻onShow轻量化”的组合后面我也会给优化建议。3. 自定义底部导航栏组件的实现拆解3.1 数据驱动结构别把tab写死在模板里定了方案之后先把导航栏本身做出来。这个组件的核心思想是数据驱动所有tab项的配置放在一个数组里模板循环渲染。这样后序要增删tab、改图标、调角标只需要改数组不需要动模板。组件我命名为custom-tabbar.vue核心数据结构如下data() { return { tabList: [ { pagePath: /pages/tab-host/index?tab0, text: 首页, icon: /static/tabbar/home.png, selectedIconPath: /static/tabbar/home-active.png, badge: 0 }, { pagePath: /pages/tab-host/index?tab1, text: 分类, icon: /static/tabbar/category.png, selectedIconPath: /static/tabbar/category-active.png, badge: 0 }, { pagePath: /pages/tab-host/index?tab2, text: 购物车, icon: /static/tabbar/cart.png, selectedIconPath: /static/tabbar/cart-active.png, badge: 3 }, { pagePath: /pages/tab-host/index?tab3, text: 我的, icon: /static/tabbar/mine.png, selectedIconPath: /static/tabbar/mine-active.png, badge: 0 } ] }; }这里的badge字段就是角标数量由外部事件更新。数组里的pagePath并不是用来真实跳转的而是为了标识“哪个tab对应哪个子组件”后面做分享参数时会用到。3.2 模板和样式图标切换、角标、安全区组件的模板部分如下template view classtabbar view v-for(item, index) in tabList :keyindex classtabbar-item :class{ active: current index } clickonItemClick(index) view classtabbar-icon-box image v-ifitem.icon classtabbar-icon :srccurrent index ? item.selectedIconPath : item.icon modeaspectFit / view v-ifitem.badge 0 classtabbar-badge {{ item.badge 99 ? 99 : item.badge }} /view /view text classtabbar-text{{ item.text }}/text /view /view /template样式上有两个容易踩坑的地方。一个是安全区适配iPhone X以后的机型底部有home indicator如果tabBar不往上让出安全区最下面的内容会被手势条挡住。safe-area-inset-bottom这个环境变量在H5和小程序上都能用但注意要写constant()再做一次兼容.tabbar { position: fixed; left: 0; right: 0; bottom: 0; display: flex; height: 100rpx; padding-bottom: constant(safe-area-inset-bottom); padding-bottom: env(safe-area-inset-bottom); background: #ffffff; box-shadow: 0 -2rpx 16rpx rgba(0, 0, 0, 0.05); z-index: 1000; }另一个是宿主页面要给底部留出空间否则tabBar会盖住页面内容.tab-host { padding-bottom: 120rpx; }如果你用uni.getSystemInfoSync()拿到了safeArea高度可以算得更精确但简单场景下上面这个固定值的做法问题不大。3.3 事件交互拦截、埋点和角标更新导航栏的点击处理我建议统一走组件事件不要在组件内部直接改页面状态methods: { onItemClick(index) { if (index this.current) return; this.$emit(tabChange, index); } }父组件收到tabChange事件后可以在这里做登录拦截、埋点上报再决定是否切换。比如我的项目里用户未登录时点击购物车tab会先弹出登录框登录成功后才继续跳转。这类逻辑放在父组件里比放在导航栏组件里更合适因为导航栏不关心业务只负责“被点击”和“展示状态”。角标的更新项目中一般有多个业务场景会触发加购、下单、优惠券变动。我用的是uniapp的全局事件总线在各处业务代码里这样触发uni.$emit(updateBadge, { tabIndex: 2, count: 5 });然后在custom-tabbar.vue里监听mounted() { uni.$on(updateBadge, this.handleBadgeUpdate); }, beforeDestroy() { uni.$off(updateBadge, this.handleBadgeUpdate); }, methods: { handleBadgeUpdate({ tabIndex, count }) { this.tabList[tabIndex].badge count; } }用$off清理是必须的不然页面销毁后事件回调依然存在容易造成内存泄漏严重的时候还会出现“销毁页面的角标把新页面的角标改了”这种串数据问题。4. 闪烁问题根因不是玄学是生命周期和渲染时机在作怪4.1 先把“闪烁”分清楚白屏、跳变、还是闪图排查闪烁问题第一步不是急着改代码而是先弄清楚用户看到的“闪”到底是哪一种。我见过三种典型形态它们的根因完全不同白屏/空屏一瞬切换后短时间内页面内容是纯白或者纯空然后才加载出来。通常是页面被销毁重建或者新页面首次渲染还没完成。内容跳变切过来时数据先显示旧状态比如空列表等异步请求返回后才变成新数据看起来就像页面“跳”了一下。图标闪一下tab图标在选中和未选中之间切换时图片先加载再显示或者字体图标先渲染成方框再变成正常图标。这三种形态可能同时存在也可能只出现一种。如果你不区分就直接开改很容易改错方向。4.2 根因一页面销毁重建一切从零开始这是最核心的闪烁来源。前面说了uni.reLaunch会把当前页面从页面栈中移除然后重新创建一个新页面。新页面创建的过程包括初始化vue实例、执行created/mounted生命周期、渲染基础DOM结构、编译样式、请求数据、数据返回后再次更新DOM。这一整个链路下来即使本地缓存做得再好也至少需要几百毫秒。在低端安卓机上这个时间可能直接拉长到一两秒。用户看到的现象就是点了tab之后当前页面先消失然后白屏一段时间新页面才姗姗来迟。在“自绘组件多页面”这种方案里如果你用的是reLaunch或redirectTo闪烁几乎是必然的因为每次切tab都等于做了一次完整的页面跳转。4.3 根因二onShow里的重复副作用还有一种很隐蔽的闪烁发生在页面没有销毁、但每次切tab都触发onShow的场景比如用原生tabBar或官方custom模式。onShow生命周期在页面每次从隐藏变为可见时都会触发。很多项目会在onShow里写拉取列表的逻辑这本身没错但有些写法是“先清空再拉取”onShow() { this.list []; // 先清空列表让视图变成空状态 this.fetchData(); // 再异步请求新数据 }这么做会导致页面一显示就变成空白等请求返回后又是一整个列表塞进来的视觉跳动。在用户看来那就是“闪了一下”。还有人在onShow里做了this.currentTab xxx之类的赋值破坏了当前的DOM状态也会造成闪烁。4.4 根因三图片、字体按需加载的闪烁这个坑特别容易出现在导航栏图标和页面里的iconfont上。页面首次切换过来时如果tab图标是网络图片而图片还没有缓存image组件会先留一片空白或者灰底等图片下载完才显示出来。一次两次还好频繁切换时每次都要重新踩一遍加载延迟。iconfont的闪烁则是另一个维度字体文件如果懒加载或者加载时机晚于页面渲染图标会先显示成方框或者乱码字体就绪后才“纠正”过来表现为内容猛地跳变一下。4.5 根因四导航栏渲染时序和内容不同步最后一种闪烁来自“层级错位”。App端使用原生tabBar时tabBar渲染在原生层页面内容渲染在webview层两个层是独立渲染的。切换tab的瞬间原生tabBar立刻切换了选中态但因为webview里的新页面还没渲染完成顶部和中间区域是白的视觉上就会觉得整个画面“闪了一下”。再说白一点tabBar是“秒切”的内容却是“慢半拍”的两者不同步就造成了撕裂感。这个问题在官方custom模式和原生tabBar下都有单页多视图方案因为压根不存在页面切换所以天然避开了这一层。5. 根治闪烁页面常驻与生命周期治理5.1 核心思路让子组件永远不被销毁针对上面的根因我最终采用的方案核心就是让tab内容常驻。宿主页面结构大概长这样template view classtab-host view v-showcurrentTab 0 classtab-page-content home-page refhomePage / /view view v-showcurrentTab 1 classtab-page-content category-page refcategoryPage / /view view v-showcurrentTab 2 classtab-page-content cart-page refcartPage / /view view v-showcurrentTab 3 classtab-page-content mine-page refminePage / /view custom-tabbar :currentcurrentTab tabChangeonTabChange / /view /template四个子组件全部挂在宿主页面下第一次进页面时按需挂载之后就一直常驻。切换tab时只是display:none和display:block之间的切换没有销毁、没有重建、没有重新走onLoad因此也就不存在白屏和生命周期重复触发的闪烁。父组件的切换逻辑也很简单methods: { onTabChange(index) { this.currentTab index; // 这里可以做业务埋点、登录拦截等 } }5.2 懒挂载避免首屏一次性创建四个子组件单页多视图方案被吐槽最多的问题就是首屏性能。如果四个子组件全部用静态v-show挂着首屏会同时执行四个组件的created、mounted所有子组件的首屏请求会一把梭发出去既慢又浪费流量。我的做法是给每个tab加一个“是否已挂载”的标记数组模板里用v-if控制首次挂载用v-show控制显隐view v-showcurrentTab 0 home-page v-ifmountedFlags[0] / /view view v-showcurrentTab 1 category-page v-ifmountedFlags[1] / /viewdata() { return { currentTab: 0, mountedFlags: [true, false, false, false] }; }, methods: { onTabChange(index) { this.currentTab index; if (!this.mountedFlags[index]) { this.$set(this.mountedFlags, index, true); } } }首屏只挂载第一个tab其他tab在用户第一次切换时才真正创建。这里有个小权衡要注意首次切换到一个未挂载过的tab时因为组件是第一次渲染还是会有一次轻微的渲染延迟但这只是在“第一次”之后切换就完全没有闪烁了。如果想让首次切换也不卡可以在宿主页面onReady后利用requestIdleCallback或者setTimeout提前挂载高频tab把渲染分散到空闲时间。5.3 用$refs手动刷新替代onShow重复触发多页面方案里依赖onShow刷新数据单页多视图方案里就没有onShow了那数据刷新怎么做答案是按需手动刷新。我在子组件里暴露出数据加载方法父组件在需要的时候通过$refs调用// child component: cart-page.vue methods: { loadData() { // 拉取购物车列表、计算总价 this.fetchCartList(); } }// parent onTabChange(index) { this.currentTab index; // 比如切到购物车tab时如果购物车数据尚未初始化才触发加载 if (index 2 !this.cartLoaded) { this.$refs.cartPage.loadData(); this.cartLoaded true; } }这种模式的收益是很明显的数据只在真正需要的时候加载一次之后无论怎么切换都不会重新请求页面保持的就是用户上次离开时的样子。购物车的勾选状态、列表的滚动位置、表单的已输入内容全都天然保留不需要额外写缓存逻辑。这在多页面方案里简直不敢想。5.4 图片字体预加载和本地化针对图标闪图的问题我有两个建议。第一个是能本地就本地tab图标直接放到static目录随包发出去不要让tabBar的图标走网络加载这是最省心的方案。如果你用的是iconfont字体图标更香因为字体是纯色矢量图选中态直接通过color切换连图片资源切换都省了彻底不存在“图标闪一下”的问题。我这次项目因为设计稿的图标是线性风格我就直接把所有图标做成了iconfont。导航栏渲染时选中和未选中只是文字颜色不同切换的观感非常干净。第二个是网络图标预加载。如果因为特殊原因比如运营后台动态配置图标必须走网络那在App启动或宿主页面onLoad时先用uni.getImageInfo把图标缓存下来onLoad() { this.tabList.forEach(item { uni.getImageInfo({ src: item.icon, success: () {} }); uni.getImageInfo({ src: item.selectedIconPath, success: () {} }); }); }这个方法没有界面上的加载显示但能让图片提前进缓存后面image组件渲染时直接读缓存也就不会白了。5.5 多页面方案下的次优解保留onShow但做轻量化如果你因为业务原因还是得用多页面官方custom模式那闪烁问题可以用“降级策略”来缓解虽然不能根除但能刷掉大部分感知。基本思路是让onShow里的逻辑变得足够轻。不要在onShow里清空列表不要在onShow里做耗时同步操作不要每次切tab都重新拉全部数据。可以给数据加载加一个时间戳或版本号只有数据过期时才重新请求onShow() { const lastTime this.lastFetchTime || 0; const now Date.now(); // 5分钟内不重复拉取 if (now - lastTime 5 * 60 * 1000) { this.fetchList(); this.lastFetchTime now; } }同时在数据加载期间用骨架屏或占位组件填充而不是直接清空页面数据。这样用户切回来时看到的是“旧数据加载状态”而不是“空白页突然满屏”视觉上的闪烁感会减轻很多。6. 多端适配与踩坑记录H5、小程序、App的差异6.1 H5端URL参数和浏览器前进后退的处理单页多视图方案在H5端有一个必须处理的点浏览器的前进后退。因为所有tab都寄生在同一个URL里用户点击浏览器返回时不会自动切回上一个tab甚至可能直接退出宿主页面。我的做法是在宿主页面的onLoad里读取URL参数通过?tab2来定位初始tabonLoad(options) { const tab Number(options.tab || 0); if (!isNaN(tab) tab 0 tab this.tabCount) { this.currentTab tab; this.$set(this.mountedFlags, tab, true); } }这样处理之后包含tab参数的分享链接在H5端打开时能直接定位到对应tab。分享路径的生成也很简单在导航栏点击处理逻辑里拼出/pages/tab-host/index?tab${index}再交给分享组件使用。6.2 小程序端分享参数和导航栏标题小程序端的分享原理和H5类似。用户当前停留在第几个tab转发出去时就在path后面拼上tab参数onShareAppMessage() { return { title: 这是第 (this.currentTab 1) 个tab, path: /pages/tab-host/index?tab this.currentTab }; }小程序扫码进入同理在onLoad里解析参数设置currentTab。还要注意一点页面标题不会因为你切到“购物车”就自动变成“购物车”。原生tabBar模式是自动跟着tab配置切换标题的单页多视图模式下需要用uni.setNavigationBarTitle手动设置watch: { currentTab(newIndex) { uni.setNavigationBarTitle({ title: this.tabList[newIndex].text }); } }这个细节很容易漏漏了之后用户在某个tab里看到的标题一直是宿主页面的名字体验很奇怪。6.3 App端长列表常驻内存和低端机性能单页多视图在App端最大的风险是内存占用。四个子组件常驻意味着四个页面的所有DOM节点和数据都活在一起。如果某个子tab是超长列表滑动产生的DOM节点会一直占着内存App长时间使用下来内存曲线可能越来越难看。我目前的做法是在低端机上做“两态降级”。如果当前手机内存小于某个阈值通过uni.getSystemInfoSync()拿到的memorySize判断就把单页多视图降级成“多页面组件复刻”虽然牺牲了切换流畅度但至少保住稳定性。这个逻辑用条件编译包一层只在App端生效H5和小程序不受影响。6.4 其他容易被忽略的坑再记三个实际项目中踩过的小坑。第一个是安全区在不同端的表现差异。env(safe-area-inset-bottom)在iOS上基本没问题部分安卓WebView不认识这个变量这时候需要单独降级处理在App端可以用uni.getSystemInfoSync().safeAreaInsets.bottom来计算并动态设置padding比纯CSS稳。第二个是低端安卓首次渲染iconfont会闪方框。解决方式是在App的main.js里提前用uni.loadFontFace加载字体文件加载成功后再渲染导航栏别把字体加载留到页面渲染过程中。第三个是z-index打架的问题。自定义导航栏用了position: fixed; z-index: 1000之后如果某个tab页面里也有弹层、popup等高z-index组件需要在弹层打开时临时把tabBar的z-index调低否则会出现弹层被tabBar挡住的诡异情况。我的处理方式是提供一个hideTabbar的方法弹层打开时调用关闭时恢复。这套自定义导航栏加闪烁治理的方案我目前已经跑了好几个版本线上反馈最明显的变化就是切换tab不再有那种“掉帧白屏”的廉价感。坦白说单页多视图并不是所有场景的最优解它牺牲了原生页面栈的一些能力换来了视觉上的连贯和状态上的持久如果你的tab页面普遍很重或者分享定位是硬需求那还是回到官方custom模式配轻量化onShow更稳妥。但如果你和我一样核心痛点就是切换太散、闪烁明显这个方案值得在你下一次项目里试试。
RELATED

相关推荐

TensorFlow 2024实战:安装避坑、模型训练与PyTorch选型指南

TensorFlow 2024实战:安装避坑、模型训练与PyTorch选型指南

跟不少朋友聊过,2024年这个时间点谈“tensorflow”好像有点“过气明星”的味道,毕竟论文圈、开源模型、大模型相关的主流工具链,这几年几乎都被PyTorch占了。但说真的,作为一个从TensorFlow 1.x一路用过来的老用户,我的…

📅 2026/10/1 6:27:45
B站m4s音频提取转MP3:ffmpeg批量处理与元数据整理

B站m4s音频提取转MP3:ffmpeg批量处理与元数据整理

1. 先把B站的视频文件结构摸清楚聊 b站视频下载转 mp3 这件事,很多人第一反应是去搜"哪个网站能一键转",但我自己折腾过几轮之后发现,真正卡住你的从来不是"找不到工具",而是根本不知道 B站 把一个视频拆成了…

📅 2026/10/1 6:22:44
用FineReport快速搭建大数据看板:从数据到可视化的完整实践

用FineReport快速搭建大数据看板:从数据到可视化的完整实践

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

📅 2026/10/1 6:22:44
MORE NEWS

更多资讯

📰

RAG问答准确度提升实战:检索、重排、生成全链路优化

做 RAG 应用的朋友应该都有过这种体验:知识库明明塞了几百份文档,问个具体问题,答案却要么答非所问,要么一本正经地编出文档里根本没有的内容。我前几个月接手了一个内部知识库问答系统,线上反馈最多的就是“搜不到”“…

📰

AI人工智能,使用Cursor+TaoToken不写代码开发微信小程序!

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

📰

如何安装VASP?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 …

📰

Kimi K3 深度评测:AI Agent 与 Kimi Code 实战,多模态与开源能力值不值得入手?

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

📰

换个领域还有效吗?一次冻结配置的迁移评测——SciFact 到 NFCorpus

换个领域还有效吗?一次冻结配置的迁移评测——SciFact 到 NFCorpus 系列:从最小复现到可检验的科研问题日期:2026-09-30适合读者:研究生、科研新人、工程型研究者实际范围:NFCorpus 的 BEIR 导出语料全部 3633 篇文档、…

📰

从零实现自定义视频播放控件:属性、事件与实战踩坑指南

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

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬