UIPageViewController核心原理与生产级实践指南
1. 这个“左右滑动”到底在解决什么真实问题很多人第一次看到UIPageViewController第一反应是“不就是个翻页效果吗用UIScrollView加个pagingEnabled不就完事了”——我当年也是这么想的直到在某跨平台系统里负责一个教育类App的课程导航模块。当时用纯UIScrollView实现了五页课程卡片逻辑看似简单监听scrollViewDidEndDecelerating根据contentOffset.x / bounds.width算出当前页再更新底部指示器。上线两周后用户反馈集中爆发“滑到第二页突然跳回第一页”“手指刚松开就闪退”“从第三页快速滑向第五页中间页完全没加载空白两秒”查日志发现UIScrollView的contentOffset在快速滑动中存在非整数偏移、惯性滚动未结束时多次触发回调、页面复用逻辑与delegate响应时机错位……这些都不是 Bug而是UIScrollView作为通用滚动容器的设计本意——它不承诺“页”的语义只负责“滚动”。而UIPageViewController的核心价值恰恰在于它把“页”这个业务概念从开发者手动维护的状态机升级为系统级的生命周期管理对象。它不是炫技组件而是为三类典型场景量身定制的解决方案内容分步引导如新用户首次启动的四步教程每页需独立初始化、预加载下一页、销毁上一页长文档/电子书阅读如 PDF 章节切换每页可能含复杂渲染、手势冲突处理、内存敏感多状态表单流程如注册流程的“基本信息→验证→设置密码”页间数据传递、返回时状态回溯、跳转合法性校验。关键词里虽未明写但所有实际落地项目都绕不开三个硬性需求页状态隔离A页崩溃不影响B页、预加载边界控制不能无限制加载下一页导致 OOM、手势优先级仲裁当页内有UITableView时如何区分“上下滑动列表”和“左右翻页”。这些不是可选项而是UIPageViewController存在的根本理由。如果你的项目只是做五个静态图片轮播那真没必要上它——但凡涉及页内交互、状态持久化、或未来要扩展页数它就是不可替代的基础设施。提示别被“ViewController”后缀迷惑。UIPageViewController本身不渲染任何 UI它只做三件事协调页容器、管理页生命周期、调度翻页动画。真正的内容必须由你提供的子UIViewController承载。这决定了它的学习曲线不是“怎么用”而是“怎么设计页控制器”。2. 为什么必须选UIPageViewController而非UIScrollView或第三方库市面上替代方案不少但真正经受住生产环境考验的只有UIPageViewController。我们来拆解三种主流方案在真实项目中的表现方案内存占用5页含图表手势冲突处理难度页状态隔离能力系统动画兼容性维护成本UIScrollView 手动分页中需自行管理视图复用高需重写hitTest无所有页共享同一view生命周期低自定义动画易卡顿高每次 iOS 更新都可能破坏偏移计算第三方 PageView 库如Pageboy低轻量级中依赖库作者对UIGestureRecognizer的理解中部分库不支持页内viewWillAppear中动画参数受限中需跟进库更新兼容新 APIUIPageViewController高但可控低原生手势识别器自动仲裁强每页为独立UIViewController高直接复用UIView动画系统低iOS 5 稳定 API无 Breaking Change关键差异点在于手势仲裁机制。UIPageViewController内置的UIPanGestureRecognizer会主动检测滑动手势的“方向倾向性”当水平位移 垂直位移 1.5 倍时才接管事件并取消子视图的手势响应。这意味着你可以在页内放一个UITableView用户垂直滑动时表格正常滚动只有当手指明显横向移动时才会触发翻页。而UIScrollView方案需要你手动实现gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:并计算角度稍有不慎就会出现“一碰表格就翻页”的灾难性体验。另一个常被忽视的优势是动画可预测性。UIPageViewController的翻页动画本质是UIView的transitionWithView:duration:options:animations:completion:封装所有参数如curveEaseInOut、transitionCurlUp都映射到系统底层动画引擎。我们在某金融 App 的行情 K 线页中测试过当页内有高频刷新的CADisplayLink时UIPageViewController的翻页动画帧率稳定在 58~60 FPS而自定义UIScrollView方案在相同负载下掉帧至 32 FPS——因为后者在layoutSubviews中反复计算contentOffset与CADisplayLink的刷新周期形成竞争。注意UIPageViewController的内存占用并非“天生高”而是可精确控制。它的dataSource协议要求你实现pageViewController:viewControllerBefore:和pageViewController:viewControllerAfter:这意味着你可以按需创建页控制器如只缓存当前页前后各一页而非一次性加载全部。很多团队误以为它“吃内存”其实是没正确实现数据源的懒加载逻辑。3. 从零搭建一个生产级页控制器核心协议与生命周期详解UIPageViewController的骨架极简但填满血肉需要理解三个协议方法的调用时序与边界条件。我们以一个课程学习 App 的页控制器为例逐步展开3.1 数据源协议不只是“返回上一页/下一页”UIPageViewControllerDataSource是整个翻页逻辑的中枢但它的两个核心方法常被误用func pageViewController( _ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController ) - UIViewController? { // ❌ 错误直接返回 index - 1 对应的控制器 // let index pages.firstIndex(of: viewController) // return pages[index! - 1] // ✅ 正确基于当前页控制器的唯一标识查找 guard let currentVC viewController as? CoursePageViewController else { return nil } let currentIndex currentVC.pageIndex guard currentIndex 0 else { return nil } return makePageViewController(at: currentIndex - 1) } func pageViewController( _ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController ) - UIViewController? { guard let currentVC viewController as? CoursePageViewController else { return nil } let currentIndex currentVC.pageIndex guard currentIndex totalPages - 1 else { return nil } return makePageViewController(at: currentIndex 1) }关键点在于永远不要依赖pages数组索引而要通过页控制器自身的属性定位。因为UIPageViewController可能同时持有多个页控制器实例如预加载下一页时数组索引会因复用而失效。我们让每个CoursePageViewController持有一个pageIndex: Int属性在初始化时注入这样无论实例如何流转位置信息始终可靠。3.2 代理协议捕捉翻页意图与完成状态UIPageViewControllerDelegate的两个方法常被混淆pageViewController:willTransitionTo:在翻页动画开始前触发此时用户手指尚未松开但系统已决定要翻到哪一页。这是拦截非法跳转的黄金时机。例如在表单流程中若用户未填写必填项可在此处调用setViewControllers(_:direction:animated:completion:)强制切回当前页并弹出提示。pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:在翻页动画结束后触发。注意transitionCompleted参数当用户中途取消翻页如滑动一半又拖回此值为false此时你不应更新任何业务状态。我们曾在一个医疗问诊 App 中遇到坑医生在“病史采集”页填写到一半误触边缘滑动想翻页transitionCompleted为false但团队错误地将此页标记为“已访问”导致后续流程校验失败。修复方案就是在willTransitionTo中先冻结当前页状态仅在transitionCompleted true时才提交。3.3 页面控制器的生命周期比普通 ViewController 更复杂UIPageViewController管理的子页控制器其生命周期事件触发顺序与常规不同1. makePageViewController(at: 0) → init() 2. 第一页显示 → viewWillAppear() → viewDidAppear() 3. 用户滑向第二页 → 第一页viewWillDisappear() → 第二页viewWillAppear() 此时第二页已创建但未显示 4. 翻页动画完成 → 第一页viewDidDisappear() → 第二页viewDidAppear()重点在于viewWillAppear在第二页尚未完全显示时就已触发。这意味着如果你在viewWillAppear中启动网络请求加载数据用户会看到空白页等待几秒。正确做法是在viewWillAppear中启动轻量级准备如配置 UI 元素在viewDidAppear中触发耗时操作如URLSession请求。我们甚至在viewDidAppear中加了 0.1 秒延迟确保动画彻底结束再开始加载避免视觉卡顿。实操心得永远在viewDidDisappear中释放页内资源。某次在页内使用AVPlayer播放视频忘记在viewDidDisappear中调用player.pause()导致用户翻页后背景音仍在播放。UIPageViewController不会自动帮你管理子页的媒体资源这是开发者的责任。4. 手势冲突实战当页内有 UITableView/UICollectionView 时怎么办这是UIPageViewController最高频的“崩溃现场”。用户抱怨“一碰表格就翻页”、“想拉下拉刷新结果翻到上一页”。根本原因在于UIPageViewController的UIPanGestureRecognizer和子页UITableView的UIPanGestureRecognizer同时监听水平滑动系统默认让第一个识别器获胜。解决方案不是禁用某个手势而是让它们协同工作。核心思路是让页控制器的手势识别器“谦让”仅在用户明确想翻页时才介入。4.1 重写gestureRecognizerShouldBegin:实现智能仲裁在UIPageViewController的子类中重写此方法override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) - Bool { guard let panGR gestureRecognizer as? UIPanGestureRecognizer else { return true } // 获取手势起始点在页控制器坐标系中的位置 let translation panGR.translation(in: self.view) let velocity panGR.velocity(in: self.view) // 规则1如果滑动起始点在页边缘 40pt 内优先翻页 let touchPoint panGR.location(in: self.view) let isEdgeTouch touchPoint.x 40 || touchPoint.x self.view.bounds.width - 40 // 规则2如果水平速度 垂直速度 2 倍且位移 20pt判定为翻页意图 let horizontalVelocity abs(velocity.x) let verticalVelocity abs(velocity.y) let isHorizontalSwipe horizontalVelocity verticalVelocity * 2 abs(translation.x) 20 // 规则3如果页内有可滚动视图且其 contentOffset.y ! 0即不在顶部禁止翻页 if let scrollView currentPageViewController?.view.subviews.first(where: { $0 is UIScrollView }) as? UIScrollView { if scrollView.contentOffset.y ! 0 { return false // 下拉刷新中禁止翻页 } } return isEdgeTouch || isHorizontalSwipe }这段代码实现了三层防御边缘优先用户从屏幕左右边缘开始滑动大概率想翻页速度导向快速水平滑动时系统更信任用户的翻页意图状态感知检测页内UIScrollView是否处于可下拉状态避免打断刷新。4.2 处理下拉刷新冲突UIRefreshControl的特殊适配UIRefreshControl的下拉阈值是 60pt而UIPageViewController默认在 30pt 就触发翻页。我们通过动态调整UIPageViewController的panGestureRecognizer的minimumNumberOfTouches来解决// 在页控制器的 viewDidLoad 中 if #available(iOS 15.0, *) { // iOS 15 支持 refreshControl 的新 API tableView.refreshControl?.tintColor .systemBlue // 关键设置刷新控件的触发阈值高于翻页阈值 tableView.refreshControl?.attributedTitle NSAttributedString(string: 下拉刷新) } else { // iOS 14 及以下通过 KVC 修改私有属性需谨慎 let refreshControl tableView.refreshControl! let originalTarget refreshControl.value(forKey: _target)! let originalAction refreshControl.value(forKey: _action)! // 此处省略具体 KVC 调用实践中建议降级为手动实现刷新逻辑 }更稳妥的做法是在scrollViewWillBeginDragging中临时禁用UIPageViewController的手势func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { // 检测是否为下拉刷新 if scrollView.contentOffset.y -60 { pageViewController?.panGestureRecognizer.isEnabled false } } func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { DispatchQueue.main.asyncAfter(deadline: .now() 0.1) { self.pageViewController?.panGestureRecognizer.isEnabled true } }踩坑实录某次我们未在scrollViewDidEndDragging中恢复手势导致用户下拉刷新后后续所有水平滑动都失效。原因是UIPageViewController的手势被永久禁用而UIScrollView的isDragging属性在动画结束后才变为false所以恢复时机必须延后。5. 性能优化与内存控制避免 OOM 的七种实践UIPageViewController最大的性能陷阱是“页控制器无限创建”。默认情况下当你滑到第 3 页时它可能已创建了第 1、2、3、4 页的实例。对于含大量图片或视频的页内存会指数级增长。5.1 实施三级缓存策略我们采用基于 LRU最近最少使用的缓存模型缓存层级存储内容生命周期容量上限触发条件活跃层当前页控制器viewDidAppear到viewDidDisappear1 个用户正在查看预热层当前页的前后各一页创建后常驻内存2 个dataSource返回时创建冷存储层已访问过的页数据非控制器viewDidDisappear后保留5 个用于快速重建实现关键在makePageViewController(at:)方法private var activePageCache: [Int: CoursePageViewController] [:] private var warmPageCache: [Int: CoursePageViewController] [:] private var coldDataCache: [Int: CoursePageData] [:] func makePageViewController(at index: Int) - CoursePageViewController { // 1. 优先从活跃层取 if let vc activePageCache[index] { return vc } // 2. 次选预热层 if let vc warmPageCache[index] { warmPageCache.removeValue(forKey: index) activePageCache[index] vc return vc } // 3. 最后创建新实例 let vc CoursePageViewController(index: index) activePageCache[index] vc // 4. 预热相邻页但不超过容量 if index 0 warmPageCache.count 2 { warmPageCache[index - 1] makePageViewController(at: index - 1) } if index totalPages - 1 warmPageCache.count 2 { warmPageCache[index 1] makePageViewController(at: index 1) } return vc }5.2 监控内存压力在 didReceiveMemoryWarning 中主动清理UIPageViewController不响应didReceiveMemoryWarning但你的页控制器可以override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // 清理预热层保留活跃层 warmPageCache.removeAll() // 通知页内释放非关键资源 activePageCache.values.forEach { $0.releaseNonEssentialResources() } // 清理冷数据缓存保留最近访问的3个 let sortedKeys coldDataCache.keys.sorted { // 按最后访问时间排序此处简化为索引倒序 return $0 $1 } for key in sortedKeys.suffix(from: 3) { coldDataCache.removeValue(forKey: key) } }5.3 图片加载专项优化页内图片是内存杀手。我们强制所有页控制器使用统一的图片加载器并设置严格约束尺寸裁剪服务端返回3x图片时客户端按页宽等比缩放避免加载 2000px 宽图显示在 375px 屏幕上内存缓存上限NSCache设置countLimit 20最多缓存 20 张图totalCostLimit 100_000_000100MB磁盘缓存策略仅缓存PNG/JPEG格式WebP图片不缓存解码耗 CPU在CoursePageViewController的viewDidLoad中override func viewDidLoad() { super.viewDidLoad() // 关键设置图片加载器的内存预算 imageLoader.memoryCache.totalCostLimit 50_000_000 // 50MB imageLoader.memoryCache.countLimit 10 // 预加载当前页图片但延迟 0.3 秒避免阻塞 UI DispatchQueue.main.asyncAfter(deadline: .now() 0.3) { self.loadImagesForCurrentPage() } }经验总结在 iOS 16 设备上我们发现UIPageViewController的transitionStyle从.scroll切换为.pageCurl后内存峰值下降 18%。因为卷曲动画使用 GPU 渲染减少了 CPU 的CALayer合成压力。但这仅适用于内容静态的页动态内容如实时图表仍推荐.scroll。6. 调试与排错定位“翻页失效”“白屏”“卡顿”的完整链路生产环境中UIPageViewController的问题往往表现为“玄学现象”。以下是我们的标准化排查清单6.1 翻页完全失效从手势识别器开始检查现象手指滑动无响应dataSource方法从未被调用。排查链路检查UIPageViewController的view是否被其他视图遮挡如半透明蒙层UIView的userInteractionEnabled true在viewDidLoad中打印self.panGestureRecognizer.delegate确认未被意外赋值为nil用Reveal工具检查panGestureRecognizer的enabled和cancelsTouchesInView属性是否为true在gestureRecognizerShouldBegin:中添加断点确认是否被提前返回false。我们曾在一个项目中发现页控制器嵌套在UIStackView中而UIStackView的distribution .fillEqually导致页控制器view的frame高度为0panGestureRecognizer因无有效响应区域而失效。修复只需在viewDidLayoutSubviews中强制设置self.view.frame self.view.superview!.bounds。6.2 白屏/黑屏页控制器未正确添加子视图现象翻页动画执行但新页内容为空白。排查链路检查页控制器的view是否已添加到父视图viewController.view.superview ! nil在页控制器的viewDidLoad中确认self.view.backgroundColor不为.clear透明背景在深色模式下易被误判为白屏使用Xcode View Debugger检查页控制器的view层级确认其subviews中包含你期望的 UI 元素关键检查页控制器的loadView是否被重写且未调用super.loadView()导致self.view为nil。6.3 卡顿分析主线程耗时操作现象翻页动画不流畅FPS 低于 45。工具链Xcode 的Time Profiler过滤CA::Transaction::commit查看CA::Layer::display耗时Core Animation调试开启Color Blended Layers红色区域表示过度绘制Memory Graph检查是否存在循环引用如页控制器持有delegate未设为weak。我们定位过一个典型卡顿页控制器中使用UIVisualEffectView作为毛玻璃背景但未设置effect nil在viewDidDisappear中导致离屏渲染持续占用 GPU。修复后翻页帧率从 38 FPS 提升至 59 FPS。最后分享一个隐藏技巧在UIPageViewController的viewDidLoad中调用self.transitionCoordinator?.notifyWhenInteractionEnds({ _ in })可捕获用户“松开手指”的精确时刻。这比scrollViewDidEndDecelerating更精准适合做翻页完成后的埋点上报。

相关新闻

Win10下HASP/Aladdin/Sentinel加密狗驱动安装与排障实战指南

Win10下HASP/Aladdin/Sentinel加密狗驱动安装与排障实战指南

简介:HASP(Aladdin Sentinel)加密狗驱动程序支持Windows 10系统,专为使用Sentinel硬件加密狗的软件用户、企业IT管理员及软件授权维护人员准备,可解决受保护软件在最新系统上无法识别加密狗、驱动不兼容、授权失效等问…

2026/10/15 15:59:16 阅读更多 →
SpringBoot整合Kaptcha验证码实战:配置驱动与生产避坑指南

SpringBoot整合Kaptcha验证码实战:配置驱动与生产避坑指南

1. 为什么SpringBoot项目还在手写验证码逻辑?我第一次接手一个老系统时,看到登录页的验证码是用BufferedImage硬生生画出来的——三行干扰线、四个随机字符、背景色随机、字体大小手动计算偏移。当时觉得挺酷,直到要加滑动拼图验证&#xff0…

2026/10/15 15:59:16 阅读更多 →
Cyclone V SoC嵌入式异构设计实战:从选型到量产全流程复盘

Cyclone V SoC嵌入式异构设计实战:从选型到量产全流程复盘

做嵌入式这几年,经历的项目不算少,但真正把一颗芯片从选型、硬件、软件、量产维护整个链路完整走一遍的,Cyclone V SoC这个项目算是头一遭。产品是一款工业现场的采集控制设备,需要ARM端跑协议栈和业务逻辑,FPGA端做高…

2026/10/15 15:59:16 阅读更多 →

最新新闻

herdr-gpui Teleport 深度解析:带着未提交改动、运行中进程和 Agent 会话跨主机迁移工作树

herdr-gpui Teleport 深度解析:带着未提交改动、运行中进程和 Agent 会话跨主机迁移工作树

【免费下载链接】herdr-gpui Native client for Herdr on macOS, Linux, and Windows, built with Rust and GPUI. View terminal sessions, workspaces, Git worktrees, and agent activity through your local Herdr daemon. 项目地址: https://gitcode.com/gh_mi…

2026/10/15 17:31:51 阅读更多 →
共享儿女填补孤独缺口,却替代不了子女的那通电话

共享儿女填补孤独缺口,却替代不了子女的那通电话

(知潮网)它能递给老人一把伞,却补不上子女那通电话——共享陪伴是温情,还是被明码标价的生意? 晚上七点,很多家庭的厨房里,菜凉了,筷子摆了两双,最后一双始终没动过。不是…

2026/10/15 17:31:51 阅读更多 →
Aspose.Words.Cpp 18.11:无Office依赖的C++原生Word文档处理库

Aspose.Words.Cpp 18.11:无Office依赖的C++原生Word文档处理库

简介:Aspose.Words.Cpp_18.11.zip 是面向C开发者的专业级Word文档处理SDK资源包,适用于需在无Office依赖环境下实现文档自动化生成、编辑、格式转换与批量邮件合并的中高级开发场景。资源共1150个文件,涵盖1082个头文件(h&#xf…

2026/10/15 17:31:51 阅读更多 →
Flutter时间解析避坑指南:DateTime.parse与millisecondsSinceEpoch本质解析

Flutter时间解析避坑指南:DateTime.parse与millisecondsSinceEpoch本质解析

1. 为什么看似简单的字符串转时间,却让 Flutter 开发者反复栽跟头?在某跨平台系统重构项目中,我接手了一个已上线半年的订单时间展示模块。用户反馈“部分订单时间显示为 1970-01-01”,后台日志里却明确记录着2023-08-15T14:22:37…

2026/10/15 17:31:51 阅读更多 →
Matlab概率分布与分位数实战:从选型到异常值检测

Matlab概率分布与分位数实战:从选型到异常值检测

1. 从"这组数据像什么形状"开始聊概率分布做数据分析的人都有一个共同的体会:拿到一组数据,第一件事往往不是算均值方差,而是先画个直方图看看它长什么样。这个"长什么样",在统计学里有个正式的名字&#xff…

2026/10/15 17:31:51 阅读更多 →
C++运算符避坑指南:从整数除法到短路求值,这些细节你注意了吗?

C++运算符避坑指南:从整数除法到短路求值,这些细节你注意了吗?

1. 为什么运算符值得单独写一篇笔记 刚学 C 那会儿,我总觉得运算符这东西太基础了,加减乘除谁不会啊,翻书的时候都是直接跳过的。直到后来在项目里踩了几个不大不小的坑——比如整数除法把小数部分悄悄吃掉导致金额计算差了几分钱、自增运算符…

2026/10/15 17:30:51 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

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

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

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

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

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

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

2026/10/14 16:30:29 阅读更多 →
影刀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/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练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 阅读更多 →