H5手机相机拍照上传全攻略:capture与getUserMedia选型及实现
简介面向需要实现手机相机拍照并上传照片到后台的HTML5开发者压缩包内含完整可运行的示例代码与配套资料。资源共22个文件、3.18MB主要包含HTML页面、JavaScript脚本、PHP后台处理脚本以及jpg/png演示截图、txt操作笔记和url参考链接。代码演示了input typefile capturecamera调用手机摄像头通过FileReader读取为base64实现拍照预览再利用FormData与fetch将照片提交至PHP服务器保存的全流程同时涵盖了用户权限确认、图片类型校验、PHP端移动上传文件、目录写权限及时间时区设置等常见处理细节。压缩包内另有微信中实际测试成功记录、拍照照片存储位置说明和若干关于jQuery.data、base64转换的参考文章链接方便开发者理解原理并直接复用。已有2170人学习下载适合Web开发初学者和需要在移动端快速集成拍照上传功能的技术人员。1. 手机相机拍照上传 H5为什么它不是“打开摄像头”这么简单做移动端 H5 开发的人大概率都接过这个需求让用户用手机相机拍一张照片传回后台。工单系统拍设备、体检平台传报告单、商城传实拍图场景遍地都是。可“在网页里拍照”没有“打开相机”这样的独立 API真实常用的路径只有两条input 标签的 capture 属性与 getUserMedia。前者把界面交给系统相机后者把实时取景搬进页面。它们在 Android、iOS、微信内置浏览器里各有脾气选错一次后续全是坑。这篇笔记把拍照、压缩、上传、后台接收的最小链路完整拆一遍含选型对比、canvas 截帧参数、fetch 上传代码和后台最少必会代码再附上真实机型踩坑记录。适合要快速交付上传模块的开发者也适合想少交学费的全栈新人。2. 两种拉起相机的方式capture 属性与 getUserMedia 的取舍2.1 先把“拍照”拆成四个动作再决定用什么技术很多开发者一上来就搜“H5 拍照 API”搜不到就开始焦虑。其实做一个 H5 手机相机拍照功能真实链路是四步拿到摄像头画面或唤起系统相机取一帧画面并压缩转成可上传的 Blob通过 FormData 提交后台。差异只集中在第一步。如果你只需要“拍一张传上去”对取景界面没有自定义要求input 的 capture 就是成本最低、稳定性最好的方案。如果你想在页面里嵌一个实时取景框、支持前后摄切换、加自定义遮罩那就必须用 getUserMedia同时接受它带来的权限、生命周期、iOS 兼容问题。我见过不少团队一上来就上 getUserMedia做了两周还在调 iOS 黑屏最后整个模块退回 input capture。先想清楚产品要什么再选技术这一条比任何代码都值钱。2.2 方案一input capture最少代码拉起系统相机这是最稳的路代码短到几乎不会错input idcamera-input typefile acceptimage/* captureenvironment styledisplay: none; /capture 属性写 user 代表前置相机environment 代表后置相机。它只是一个“建议”不是强制部分桌面浏览器和个别平板仍然会弹文件选择框这种降级不算 bug别浪费时间跟它较劲。运行时只需要监听 change 事件const input document.getElementById(camera-input); input.addEventListener(change, (event) { const file event.target.files[0]; if (!file) return; // 读成 dataUrl 便于后续压缩也保留 File 对象便于直接上传 const reader new FileReader(); reader.onload (e) { const dataUrl e.target.result; // 把 dataUrl 交给压缩环节 console.log(拿到文件, file.name, file.type, file.size); }; reader.readAsDataURL(file); });逻辑说明用户拍完照文件已经出现在 files[0] 里。你想传原图直接丢 FormData想压缩先把 dataUrl 交给压缩函数。FileReader 负责把文件读成 base64后续所有流程都围绕 dataUrl 展开。参数注意accept 必须写 image/*有些安卓浏览器不写就只让选文件不给拍照capture 的值建议显式写不写时部分浏览器会默认走文件选择而非相机。另外提醒一句手机原图体积按 MB 记压缩这一步无论如何省不掉。2.3 方案二getUserMedia把实时画面拉进页面要实时预览只能走这里。核心调用/** * 初始化摄像头预览 * 必须在 HTTPS 或 localhost 下调用否则浏览器直接拒绝 */ async function initCamera() { const constraints { video: { facingMode: environment, // 优先后置摄像头 width: { ideal: 1280 }, height: { ideal: 720 } }, audio: false }; try { const stream await navigator.mediaDevices.getUserMedia(constraints); const video document.getElementById(camera-preview); video.srcObject stream; video.play(); } catch (err) { // 权限拒绝、无摄像头、设备占用都在这里兜底见第 5 章 console.error(摄像头初始化失败, err); } }页面里配一个 video 标签video idcamera-preview autoplay muted playsinline width100% /videoautoplay 让流一到位就播放muted 在 iOS Safari 上基本是必备不静音画面可能不渲染playsinline 避免 iOS 直接把流推到全屏播放否则你的自定义取景框全部白做。这里最容易出现认知偏差getUserMedia 拿到的是连续的视频流 MediaStream不是照片。要得到照片必须自己从流里截一帧这个动作用 canvas 完成见下一章。两条方案对比如下对比项input capturegetUserMedia代码量极少中等实时预览无有自定义取景框不可可iOS 兼容性稳定需额外属性配合权限策略系统默认需申请且受 HTTPS 约束图片体积控制拍后压缩可先设分辨率再压缩二次拍摄/换摄像头受系统限制可完全自定义我的经验是微信内置浏览器里优先 input capture需要自定义体验再上 getUserMedia。混着写也行但“getUserMedia 失败后回退到 capture”只有后者需要写加了这层兜底整个功能才完整。3. H5 拍照核心实现canvas 截帧、图片压缩与参数设置3.1 canvas 截帧为什么必须用 video.videoWidth完成 getUserMedia 之后把画面变成图片的代码很短function captureFrame() { const video document.getElementById(camera-preview); const canvas document.createElement(canvas); // 用真实视频尺寸不要用元素的 clientWidth canvas.width video.videoWidth; canvas.height video.videoHeight; const ctx canvas.getContext(2d); ctx.drawImage(video, 0, 0, canvas.width, canvas.height); // image/jpeg 质量 0.7 是体积与画质的平衡点 return canvas.toDataURL(image/jpeg, 0.7); }逻辑说明video.videoWidth 和 video.videoHeight 才是视频流真实分辨率clientWidth 只是元素显示宽度。drawImage 的四个参数分别是目标坐标和尺寸这里把整帧视频铺满整张画布。参数理解第一个参数 image/jpeg 时第二个参数范围 010.7 日常够用如果拍的是票据、表格这类文字内容建议提到 0.85否则文字边缘会发虚。选 image/png 时质量参数被浏览器忽略体积比 JPEG 大数倍只有需要透明背景才值得。提示有人以为直接用 video 的捕获方法存成文件更“原生”但在 Safari 上经常拿不到正确的方向信息。canvas 截帧是把像素直接画出来反而少一层不确定性。3.2 图片压缩先限制边再压质量两个参数都要调光靠 JPEG 质量参数压不住手机原图。一张 4000×3000 的照片质量调到 0.5 依然轻松超过 1MB。实用做法是先限制最长边再做 JPEG 压缩。/** * 图片压缩等比缩放到最长边不超过 maxPixel * param {string} dataUrl - 原始图片的 dataUrl * param {number} maxPixel - 最长边像素上限 * param {number} quality - JPEG 质量 0~1 * returns {Promisestring} */ function compressImage(dataUrl, maxPixel 1600, quality 0.75) { return new Promise((resolve) { const img new Image(); img.onload function () { const { width, height } img; const maxSide Math.max(width, height); // 原图已经小于限制值跳过画布直接返回 if (maxSide maxPixel) { resolve(dataUrl); return; } const scale maxPixel / maxSide; const canvas document.createElement(canvas); canvas.width Math.round(width * scale); canvas.height Math.round(height * scale); canvas.getContext(2d).drawImage(img, 0, 0, canvas.width, canvas.height); resolve(canvas.toDataURL(image/jpeg, quality)); }; img.src dataUrl; }); }逻辑说明先读原图尺寸算出等比缩放比例再按新尺寸建画布绘制。缩到最长边 1600对手机和 PC 网页展示完全够用需要打印或放大裁剪的场景再提到 2560。使用方式const compressedDataUrl await compressImage( captureFrame(), // 或 FileReader 得到的 dataUrl 1600, // 最长边 0.7 // 质量 );3.3 压缩参数的三个必调项与误用差别第一最长边。绝大多数业务设 1600超大图展示需求 2560 封顶。“压到 100KB”这种指标不科学不同场景需要的边长完全不同。第二质量参数。0.7 通用0.85 适合文字截图类0.9 以上对体积影响明显但画质提升有限后端如果要做 OCR、人脸比对建议保留 0.85 以上。第三格式。如果要转 WebP用 canvas.toBlob 指定 image/webp体积通常比 JPEG 再少 20%30%但后台若限死只收 JPEG这条别碰。踩坑重灾区是把压缩参数当成写死的全局配置前端每张图都走同一套。真实业务里用户拍的是单据还是风景清晰度要求完全不一样压缩参数最好做成可配置至少由产品确认一次再定死。4. 把照片交给后台FormData、fetch 上传与后端接收最小实现4.1 从 dataUrl 到 Blob这一步省掉后端大概率拒绝压缩完是 dataUrl直接传给后台不是不行但后台通常期望 multipart/form-data 的文件格式且 dataUrl 比等价 Blob 体积大 33% 以上。先转 Blobfunction dataUrlToBlob(dataUrl) { const parts dataUrl.split(,); const mime parts[0].match(/:(.*?);/)[1]; const byteString atob(parts[1]); const bytes new Uint8Array(byteString.length); for (let i 0; i byteString.length; i) { bytes[i] byteString.charCodeAt(i); } return new Blob([bytes], { type: mime }); }逻辑说明split 去掉 dataUrl 头atob 解码 base64逐字节写入 Uint8Array再构造成 Blob。注意 Blob 的 type 来自 dataUrl 头部的 MIME 声明常见是 image/jpeg有些后台会校验这个字段。4.2 FormData 组装与带进度的上传实现真正上传只有十几行async function uploadPhoto(dataUrl) { const blob dataUrlToBlob(dataUrl); const formData new FormData(); // 第三个参数是文件名后台可能拿它做后缀校验不要省 formData.append(photo, blob, dp_ Date.now() .jpg); // 业务参数放同一个 formData比如工单号、订单号 formData.append(bizId, ORD-2024-001); try { const resp await fetch(/api/upload, { method: POST, body: formData // 注意不要手动设置 Content-Type // 浏览器会自动带上 multipart/form-data 的 boundary }); if (!resp.ok) { throw new Error(HTTP『 resp.status 』); } const json await resp.json(); if (json.code ! 0) { throw new Error(json.msg || 未知业务错误); } return json.url; } catch (err) { // 保留 dataUrl 用于重试不要直接丢弃 throw err; } }关于上传进度fetch 不提供进度事件想要进度条有两个选择。一是用 XMLHttpRequest它原生支持 upload.onprogressconst xhr new XMLHttpRequest(); xhr.open(POST, /api/upload); xhr.upload.onprogress (e) { if (!e.lengthComputable) return; const percent Math.round((e.loaded / e.total) * 100); // 用 percent 驱动页面进度条 }; xhr.onload () { // 这里拿 JSON 字符串自己 JSON.parse console.log(xhr.responseText); }; xhr.send(formData);二是用 fetch 配合后台返回的“处理中转态”模拟进度。需求没明确要做进度条时直接用 fetch干净利落。4.3 后端最少必会代码接收单文件与返回约定后端语言不限只要处理 multipart/form-data主流框架基本都有现成方案。以 Node Express multer 为例const express require(express); const multer require(multer); const path require(path); const app express(); const uploadDir path.join(__dirname, uploads); const upload multer({ storage: multer.diskStorage({ destination: uploadDir, filename: (req, file, cb) { // 用户文件名不可信重新生成时间戳文件名 const name Date.now() _ Math.round(Math.random() * 1e6); cb(null, name path.extname(file.originalname)); } }), limits: { fileSize: 8 * 1024 * 1024 } // 限 8MB防止传原图 }); app.post(/api/upload, upload.single(photo), (req, res) { if (!req.file) { return res.status(400).json({ code: 1, msg: 缺少文件 }); } // 回传可访问 URL不要把服务器存储路径直接暴露回去 res.json({ code: 0, url: /uploads/ req.file.filename, size: req.file.size }); }); app.listen(3000);参数说明upload.single 的字段名必须和前端 formData.append 的第一个参数一致不一致 multer 直接拒绝。limits.fileSize 设 8MB 是防手滑传原图正常压缩后只有 100KB1.5MB。destination 指定的 uploads 目录如果不存在要先手动创建否则保存时报错。文件上传链路到这里已经完整拍摄 → 截帧 → 压缩 → Blob → FormData → 后台落盘 → 返回 URL。真正让项目翻车的大概率不在这些主流程代码而在下一章的边界状态里。5. iOS 黑屏、方向翻转、权限拒绝H5 调相机高频踩坑与排查5.1 现象getUserMedia 在 iOS Safari 黑屏现象Android Chrome 一切正常iPhone Safari 打开页面video 区域黑块没画面也没报错有的版本允许权限后依然黑屏。原因iOS Safari 对媒体播放的策略严格摄像头流也被当媒体播放对待。如果 video 没有 muted 和 playsinline流只能拿到但不渲染或者必须等用户交互后才渲染。解决加属性且用真实 iPhone 验证别只在开发者工具的模拟器里测video idcamera-preview autoplay muted playsinline width100%/video同时初始化时主动调一次 play()把返回的 Promise 处理掉两个保险一起上。这个坑几乎每次新项目都会遇到属于必踩项。5.2 现象拍出来的照片方向不对现象canvas 截帧后图片方向和手机相册里看到的不一致有的横变竖有的竖变横同一个机型也时好时坏。原因手机保存的 JPEG 带 EXIF orientation 字段方向信息存在元数据里。canvas 截帧只保留像素数据不应用这个方向后台显示时就错位了。解决分两条路。一是拍完立刻按已知方向旋转 canvasctx.translate(canvas.width / 2, canvas.height / 2); ctx.rotate(Math.PI); // 按实际需要旋转90/180/270 都可能是对的 ctx.drawImage(video, -canvas.width / 2, -canvas.height / 2);二是用 exif-js 这类库读取原图方向在前端做矫正或把原始 orientation 传给后台统一处理。我的做法是input capture 入口在 iOS 上高频遇到方向问题必须处理getUserMedia 入口大多数情况方向正确先拿两台不同型号的 iPhone 各试一遍再决定要不要写偏转逻辑避免多做无用功。5.3 现象用户点了权限拒绝页面变成黑匣子现象第一次进入弹权限框用户点了“不允许”之后页面没有任何操作入口也不提示降级整个功能像死掉一样。原因getUserMedia 的 Promise reject 被捕获了但没区分错误类型也没给用户出路。解决区分 err.name分别处理async function initCamera() { try { const stream await navigator.mediaDevices.getUserMedia(constraints); // 正常拿到流 } catch (err) { if (err.name NotAllowedError) { // 引导去设置打开权限或直接 fallback 到 input capture fallbackToCapture(); } else if (err.name NotFoundError) { // 没有摄像头给提示 } else if (err.name NotReadableError) { // 设备被占用常见于 PC 上两个页面同时占用摄像头 } } }fallbackToCapture 就是触发那个隐藏的 input capture。权限被拒时让系统相机接管拍照功能闭环不断这是最稳的后悔药。5.4 现象上传半路失败用户拍的照片丢了现象4G/WiFi 切换时上传失败或大图超时前端没有保留照片数据用户只能重新拍一遍。原因fetch 和 XHR 默认没有重试机制也没有保存现场。网络波动一次前面的流程全白费。解决压缩完成后先存起来上传失败能重试不重拍// 拍完压缩后立刻调用 function rememberPhoto(dataUrl) { try { sessionStorage.setItem(pending_upload, dataUrl); } catch (e) { // 压缩到 1600 边长后一般不会超 sessionStorage 配额 } } // 上传失败后重试 function retryFromMemory() { const saved sessionStorage.getItem(pending_upload); if (saved) uploadPhoto(saved); }写上传功能永远保留现场是我做过十几个上传需求后的习惯。页面刷新一下能找回上一张图和让用户重新走一遍拍照流程观感差很多。6. 上线前最后一关真机验收清单与方向修正兜底链路通了代码也能跑但能不能上线要看真实机型表现。每次交付前我至少按这份清单走一轮验收项检查内容期望结果权限弹窗首次进入、拒绝后再次进入拒绝后出现降级入口或明确引导iOS Safari 预览iPhone 打开video 有实时画面不黑屏、不全屏拍照方向横拍、竖拍各来一张后台返回 URL 显示方向正确压缩体积最高清模式拍摄再压缩最长边 1600 时体积 500KB 以内弱网重试上传时切飞行模式失败后能重试不丢照片字段约定后台日志确认字段名为 photo前端后端一致无 400方向修正如果前端做不到百分百转正还有最后兜底不旋转像素把带 EXIF orientation 的原图交给后端在后台图片处理里统一转正。这比前端硬旋转更稳因为双重旋转导致的方向错误比方向错误本身更难排查。拿我自己来说每次接这类 H5 拍照上传验收阶段一定在 iOS 真机、Android 真机、微信内置 WebView 三种环境各跑一遍上述清单否则宁可不上线。有一次漏了微信 WebView结果 getUserMedia 在部分安卓微信版本里完全没有画面最后靠 fallback 到 input capture 救了场。这种教训一次就够了。这份从选型到踩坑的拆解如果能帮你绕开这些弯路我就没白写。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

技术科学:连接基础科学与工程技术的桥梁

技术科学:连接基础科学与工程技术的桥梁

不知道你有没有这种经历:在某个行业聚会上听到“技术科学”四个字,总觉得哪里见过,真要解释又开不了口。我最近在准备一个科普视频脚本,题目就叫《究竟什么是技术科学》。说实话,刚拿到这个题目时我也没太当回事&#…

2026/10/10 22:10:59 阅读更多 →
轻量级监控平台coolmonitor:Docker部署与告警配置实战

轻量级监控平台coolmonitor:Docker部署与告警配置实战

最近好几个朋友拿着同样的需求来问我:手上有两三台服务器、一台家用NAS,想上线监控,但一打开Prometheus和Grafana的部署文档就头皮发麻。又是exporter又是Alertmanager又是datasource,还没开始采数据,先被一堆名词劝退…

2026/10/10 22:10:59 阅读更多 →
论文降AI率实用指南:从检测原理到9款工具选型与改稿实操

论文降AI率实用指南:从检测原理到9款工具选型与改稿实操

论文查重过了,却被AIGC检测拦下,可能是近两年本科生最焦虑的时刻之一。你辛辛苦苦用AI辅助整理文献、润色语句,结果学校一查AI率,直接给你标了个40%,导师那边的解释还没想好措辞。我自己见过太多这种情况,也…

2026/10/10 22:09:58 阅读更多 →

最新新闻

BFO-XGBoost超参数优化:Matlab实现与避坑指南

BFO-XGBoost超参数优化:Matlab实现与避坑指南

简介:本资源面向计算机、电子信息工程、数学等专业的大学生及算法初学者,提供一套基于鳑鲏鱼优化算法(BFO)优化XGBoost的分类预测完整方案,可用于课程设计、期末大作业或毕业设计。压缩包共18个文件,约53.6…

2026/10/10 23:29:04 阅读更多 →
LSTM+Transformer混合模型实战:原理、代码与避坑全解析

LSTM+Transformer混合模型实战:原理、代码与避坑全解析

简介:面向时间序列预测学习者的一份LSTM与Transformer混合建模实战资源,定位于帮助读者掌握用深度学习组合模型处理非线性时序数据的完整流程。压缩包共13个文件,包含Python训练脚本、CSV格式的数据集、需求说明文档、预测结果对比图以及IDE辅…

2026/10/10 23:29:04 阅读更多 →
Word高效使用指南:公式冲突、文献插入与格式转换全攻略

Word高效使用指南:公式冲突、文献插入与格式转换全攻略

1. 先解决公式插入的"神仙打架":AxMath、MathType与Word自带公式打开Word写理工科论文,最让人头大的往往不是内容本身,而是公式编辑器。你在搜索引擎里搜"为什么电脑里同时安装了AxMath和MathType,在Word内用AxMat…

2026/10/10 23:29:04 阅读更多 →
ModuleNotFoundError: No module named ‘torchaudio‘ 的成因与修复策略

ModuleNotFoundError: No module named ‘torchaudio‘ 的成因与修复策略

你正在做语音数据处理或者跑一个开源AI项目,环境都配好了,pip install也执行得很顺利,结果一运行代码,屏幕啪地甩出一行红字:ModuleNotFoundError: No module named torchaudio这一行字我太熟了,做Python开…

2026/10/10 23:29:03 阅读更多 →
扩展卡尔曼与无迹卡尔曼滤波:电力系统动态状态估计实战解析

扩展卡尔曼与无迹卡尔曼滤波:电力系统动态状态估计实战解析

电力系统状态估计从“静态断面”走向“动态过程”,正在成为调度自动化里越来越绕不开的一项技术。尤其是同步相量量测单元(PMU)普及之后,量测数据的时间分辨率从秒级提升到几十毫秒级,如果仍然用传统的加权最小二乘静态…

2026/10/10 23:29:03 阅读更多 →
红外目标检测数据集:格式转换与YOLO训练避坑指南

红外目标检测数据集:格式转换与YOLO训练避坑指南

简介:YOLO红外多目标检测数据集面向目标检测学习与算法验证场景,提供1000张真实场景高质量红外图片,经LabelImg标注后附带voc(xml)、coco(json)、yolo(txt)三种格式标签,分别存放于独立文件夹,并确保标注框质量较高&am…

2026/10/10 23:28:02 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* 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 11:14:25 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* 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 1:36:08 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* 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 11:14:58 阅读更多 →

月新闻

我发现了一个新思路:用 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/10 5:23:50 阅读更多 →
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 阅读更多 →