就业市场学历问题
刚看到隔壁帖子说毕业的学校从 xx 学院变成了大学,就很好奇是不是现在 xx 学院这种二本院校在就业市场约等于大专了?有 v 友们现身说法么?
xiaohack博客专注前沿科技动态与实用技术干货分享,涵盖 AI 代理、大模型应用、编程工具、文档解析、SEO 实战、自动化部署等内容,提供开源项目教程、科技资讯日报、工具使用指南,助力开发者、AI 爱好者获取前沿技术与实战经验。
刚看到隔壁帖子说毕业的学校从 xx 学院变成了大学,就很好奇是不是现在 xx 学院这种二本院校在就业市场约等于大专了?有 v 友们现身说法么?
一些未经证实的猜测:
| 项目 | 参数 |
|---|---|
| 总参数量 | ~1 万亿 (1 Trillion) |
| 激活参数量 | 320 亿 (32B) - 仅 3% 激活率 |
| 上下文窗口 | 100 万 (1M) Tokens |
| 多模态能力 | 文本 + 视觉 + 音频 (Audio) |
| 开源许可 | MIT 协议(极致开放) |
| 硬件优化 | 深度适配 华为昇腾 910C |
看了下公众号,V4 还是没发布,发布了估计也是媒体到处宣扬的。从过年到现在一直有不少的消息说下周发,到现在还是没有,你们觉得会在这个月发布吗?我看发帖时有竞猜我加上给你们猜猜看 🤣,话说做庄有收益不
大家好,我是 在快节奏的生活里,我们常常被焦虑、失眠、注意力不集中困扰。想睡个安稳觉,想安安静静专注一会儿,想给自己一段不被打扰的放松时光,却总被各种杂音打断。 今天,给大家介绍一款开源免费的安卓应用,专注于白噪音播放! 功能特色: 技术栈: 项目已经提供构建好的安装包,只需下载安装即可使用。 1、打开下载地址,下载安装包 2、在安卓手机中运行安装包进行安装 1、环境要求: 2、克隆或下载项目源码 3、配置 Gradle:复制 4、使用 Android Studio 打开项目并同步 Gradle 依赖 5、连接设备或启动模拟器,运行项目 可以说, 推荐的开源项目已经收录到 或者访问网站,进行在线浏览: 我创建了一个开源项目交流群,方便大家在群里交流、讨论开源项目。 但是任何人在群里打任何广告,都会被 T 掉。 如果你对这个交流群感兴趣或者在使用开源项目中遇到问题,可以通过如下方式进群: 关注微信公众号:【Java陈序员】,回复【开源项目交流群】进群,或者通过公众号下方的菜单添加个人微信,并备注【开源项目交流群】,通过后拉你进群。Java陈序员。关注微信公众号:【Java陈序员】,获取开源项目分享、AI副业分享、超200本经典计算机电子书籍等。
项目介绍
XMSLEEP —— 一个专注于白噪音播放的 Android 应用,提供多种自然声音帮助您放松、专注和入眠。应用采用 Material Design 3 设计规范,界面简洁美观,操作流畅。Kotlin + Jetpack Compose + Material Design 3 + ExoPlayer/Media3快速上手
https://github.com/Tosencen/XMSLEEP/releases功能体验





本地开发
git clone https://github.com/Tosencen/XMSLEEP.git
cd XMSLEEPgradle.properties.example 为 gradle.propertiesXMSLEEP 作为一款简单的白噪音播放工具,没有广告,不用联网,无需付费,能在你失眠、疲惫、需要专注的时候,提供最治愈的声音陪伴。快去下载安装体验吧~项目地址:https://github.com/Tosencen/XMSLEEP最后
GitHub 项目,欢迎 Star:https://github.com/chenyl8848/great-open-source-projecthttps://chencoding.top:8090/#/
大家的点赞、收藏和评论都是对作者的支持,如文章对你有帮助还请点赞转发支持下,谢谢!
观察好几天了,这个 L 站每天看都有 7 ,800 贴的发帖量,但是感觉质量也不高。大部分就 1 ,2 个人跟帖。质量远不如 V 站,但是对方注册还需要邀请啊审核的。有这么高的活跃度是怎么做到的。是 ai 在哪里发帖吗
编程 Agent 会分析/解决问题,但不会积累经验。它们有印象,但没有笔记。RadioHeader 给 Claude Code 补上了这一层。
我用 Claude Code 做 iOS 的时候,遇到过一次 app 启动白屏几十秒的问题。Claude 一路查日志、翻文件、试各种排查,折腾了很久都没定位到。最后还是我想起来,另一个项目以前也出过差不多的事,让它去翻那个项目的旧记录,才找到根因——Xcode 的 scheme 设置问题。
那一刻我就很确定一件事:像 Claude Code 这样的编程 Agent ,分析问题、写代码都很强,但它们不会共享项目经验。后来 Claude Code 虽然也加了 memory ,但本质问题没变——它记得方向,记不住关键细节,更别说跨项目复用了。
项目之间的记忆完全隔离,就意味着项目 A 踩过的坑,项目 B 根本不知道。如果我自己记得”我好像遇到过这个问题”,还能手动指路,要是我也忘了呢?
现有的工具几乎都是在做"规则"层面的事。规则当然有用,但规则无很难达到“这个坑我真的踩过,而且已经知道怎么修"这种程度。做硬件产品的时候我也经常遇到这类"认知型经验"——不是文档里写了你就会的,得自己撞上、解决了,才真正印象深刻。
在没找到做编程 agent”经验"层面的工具的情况下,我自己做了一个。
RadioHeader 不是一开始设计好的,是被真实问题一步步逼出来的。
起点是单项目内的记忆缺失。Claude Code 在一个项目里工作久了,早期的经验就开始模糊。它记得"之前遇到过类似问题",但记不住具体怎么解决的。
换句话说:Agent 需要的是笔记,不是印象。 自带的 memory 记的是大致印象,而能被精确搜索到的结构化笔记才有复用价值。
我的想法很朴素:让 Claude 每次解决完问题后,主动把经验记下来。具体分两种:一种是经验条目,写进 memory/ 目录——根因、修法、注意事项,按主题组织,方便以后检索;另一种是任务日志,写进 logs/ 目录——以一个问题的解决为单位,记录背景、过程、结论,保留完整上下文。日志的文件名经过设计:日期-主题-撰写者,Agent 和人类都要署名,标清楚方便追溯。起初我会在关键节点手动提醒 Claude"同步一下项目信息",后来逐渐做成了自动化。
我把这个机制叫经验回流——完成一个任务后,经验自动流回记忆系统。每次修完 bug 、做了架构决策、踩了非直觉的坑,Claude 都把经验写回去。用 Claude Code 的 hook 机制让这个过程自动:PostToolUse hook 在写入 memory 时触发检查,Stop hook 在会话结束时提醒有没有新经验遗漏。
同一个项目里,以前要重新排查的问题,现在翻笔记就能解决。
但很快就遇到了开头那个场景:项目 A 的笔记,项目 B 搜不到。
于是我在所有项目之上建了一个全局经验中枢:~/.claude/radioheader/。
名字的由来——我喜欢 Radiohead 这个乐队,而这个全局中枢又像一个信号塔,各个项目需要的时候就从里面接收信息。RadioHeader ,就这么出现了。
架构变成了三层:
┌─────────────────────────────────┐
│ RadioHeader (全局经验中枢) │ ← 所有项目共享
├─────────────────────────────────┤
│ 项目 memory/(项目专属记忆) │ ← 当前项目
├─────────────────────────────────┤
│ 会话上下文(临时) │ ← 当前对话
└─────────────────────────────────┘
每次经验回流时,Claude 会顺手判断一下:这条经验是不是跨项目通用的?如果是,写入全局层,标注来源项目。之后任何项目遇到类似问题,先搜这里。有了 RadioHeader 这个信号塔的隐喻之后,我把经验回流叫做 Echo(回波)——经验像信号的回波一样,从项目返回信号塔。
装了之后再遇到白屏问题:
你:App 启动白屏 10 秒以上
Claude:RadioHeader 中有来自 ProjectA 的经验:
"Xcode scheme 的 Launch 配置导致 iOS app 启动白屏,
检查 scheme 设置中的相关选项……"
验证一下是否适用…… ✓ 同样的模式。正在应用修复。
不用我手动指路了。同一类问题从第二次开始,解决时间从分钟级掉到秒级。不是 AI 变聪明了,是答案已经在那里了。
跨项目共享之后冒出一个新问题:经验一旦放到全局以后,原始条目里保留的项目上下文太多,搜索噪音和 token 消耗都上来了。比如一条经验写着 [来源:DarkWriting] iCloud I/O 阻塞主线程,另一个项目用的是 CoreData 不是 iCloud——但根因相同。项目名和具体技术细节反而成了搜索障碍。
于是我加了一层精炼:短波( Shortwave )——去掉项目名、文件路径、框架细节,只保留通用知识。这不光是为了降噪,也是为了保护隐私——经验条目在精炼之前可能包含项目路径、内部命名甚至 API key ,短波会把这些全部剥离。
这样三层就接上了:经验先通过 Echo 回到 RadioHeader,再由 Shortwave 去掉项目噪音,变成可广播的通用知识。
---
id: sw-ios-task-inherits-mainactor
domain: iOS, SwiftUI, Concurrency
tags: 白屏 | 启动慢 | white screen | slow launch | 10s+ | Main Actor | Task
---
### Task {} 在 @MainActor 上下文中继承主线程,I/O 阻塞导致白屏
symptoms: 应用启动后 10s+ 白屏,首次加载卡死
cause: Task {} 在 @MainActor 标记的上下文中创建时继承主线程
fix: 使用 Task.detached(priority:) 将 I/O 操作移出主线程
注意 tags 里的"白屏"、"启动慢"、"slow launch"——这些是开发者实际会搜的词。如果只保留 "Task.detached" 这种解法关键词,这条经验就搜不到了。症状关键词比解法关键词重要得多。 经验条目删掉了症状词就等于不存在。
到这里遇到了另一个让人头疼的问题:Claude 搜到了经验,但不用。
早期我在 CLAUDE.md 里写:"遇到技术问题时先搜索 RadioHeader"。Claude 确实搜了,也找到了相关结果——然后完全忽略,直接跳进独立分析。就像你给新同事一本 wiki ,他打开看了一眼,还是选择自己摸索。
后来搞明白了:行为指令比知识描述有效得多。 在 CLAUDE.md 里写"这里有个东西可以查"没用,得写"你必须搜,搜到必须引用,禁止搜到不用"才行。这两种写法在 Agent 系统中效果差很远。
最终方案是"搜→用→追"三步强制规则:
外加一句禁令:"禁止搜到相关经验却不引用、不应用,直接跳过去做独立分析"——这句话比前面三条都管用。
前两步解决了自己不重复踩坑的问题,但我的经验仍然是一座孤岛。我遇到的问题,世界上某个人在开发中一定早就有经验了;反过来,我踩过的坑可能也正好能帮到别人。
能不能把精炼好的短波共享出去?难题不在技术,在质量治理——不能什么都往池子里丢,但我一个人也做不了人工审核。
当时我想到试试从生物学里找找灵感,结果还真找到了一个概念——Stigmergy (痕迹协作)。这是蚁群行为学里的东西:蚂蚁在路径上留信息素,走的越多越浓,没蚂蚁走的自然蒸发。不需要谁来管理,好路径自己就显现出来了。
用这个思路做知识共享的质量治理:
verified,低分归档发布也有门槛——质量评分(≥6/8 )、隐私扫描(确保没泄露路径和密钥)、去重检查。不需要管理员,好经验自己浮上来,差经验自己沉下去。
我不是做完一个 demo 就拿出来讲故事,这套东西已经在我自己手里滚了几个月。13 个项目,覆盖 iOS/SwiftUI 、Rust 、后端部署、网络代理、AI API 、Claude Code 、硬件产品 7 个技术领域。205 条原始经验,120 条精炼短波,114 条发布到社区池。(截止发稿时)
不用先研究完整设计,找一个你最近最常重复踩坑的项目,装上跑一周就知道它有没有用。
git clone https://github.com/ZaptainZ/radioheader.git
cd radioheader
./install.sh
之后在任何项目中启动 Claude Code 就生效了。
# 开启社区共享
radioheader community on
radioheader sync
GitHub:ZaptainZ/radioheader
RadioHeader 还在继续打磨,但它已经在我自己的真实项目里跑出价值了,所以我把它公开出来。开源社区帮了我很多,这次也算把自己真用出来的一套东西拿出来回馈。
MIT 协议。你要是也受不了重复踩坑,直接装上试试。有用欢迎 star ,没用也欢迎来 issue 吐槽。
AI 擅长执行明确指令,但不擅长理解复杂的业务场景、做需要权衡的技术选型、跨团队的沟通协调、从 0 到 1 的产品定义。这些“模糊地带”才是 AI 时代程序员的护城河。越靠近执行层越危险,越靠近决策层越安全。
如何合法途径通过国内支付,有经验的进来聊聊啊
昨天 claude 和 pro 刚刷新,昨晚看还是满的,今天看直接干周限了。
antigravity 官方给出的说法是,pro 就是让你尝尝鲜的,额外给了一个 1000 ai credit 的额度。可以应急使用,但是这个额度消耗具体规则也没给出来。
同时额度好像还是家庭组共享的,组 team 车的有点麻麻的。
原文:
We’re evolving Google AI plans to give you more control over how you build. Every subscription includes built-in AI credits, which can now be used for Antigravity, giving you a seamless path to scale.
Google AI Pro is the home for the practical builder, hobbyists, students, and developers who live in the IDE and don't necessarily rely on an agent. This plan features generous limits for Gemini Flash, with a baseline quota included to "taste test" our most advanced premium models.
Google AI Ultra serves as the daily driver for those shipping at the highest scale who need consistent, high-volume access to our most complex models.
If you’re on Pro but need "extra juice" for a heavy sprint or deeper access to premium models, simply top up your AI credits to customize your plan.
Keep building. Keep shipping.
我们每个人,都会死去,都会离开,会被遗忘,所有的一切,最后都会归零。
但人生,其实也在不断地重启、格式化、重装系统、恢复出厂设置。 📲📲📲
早上开车上班,随机播放到某一首歌。歌本身一般般,不作为特别推荐,可以当成 BGM 随便听听,但里面几句歌词,确实一下子戳到我了。
歌词很直白,说的很简单,甚至有点残酷:我们每个人,终究都会死去,都会离开,都会被遗忘,所有的一切,最后都会归零。
就这么一首歌,我在路上循环听了好几遍,越想越对。突然就觉得,人生这事,跟我们平时 给电脑重装系统、给手机恢复出厂设置,简直一模一样。

经常折腾电脑、手机的兄弟,应该一下就能听懂我在说什么。
每次准备重装系统前,我们都会先做一件事:备份重要文件,整理资料,做好启动 U 盘,把该保留的都留好。
但我还有个习惯:在一切准备就绪、马上就要格式化之前,我会放开手脚,随便折腾。
平时不敢装的软件,怕它乱要权限、乱改系统,这会儿直接装上试试;平时一直用 A 方案,觉得 B 是替代品懒得换,这会儿也装上体验对比一下,说不定更好用;甚至那些担心带病毒、有风险的黑客工具,也敢拿出来玩一玩。
反正系统马上就要清空了,坏了也无所谓,乱了也不心疼。
等折腾够了,点一下格式化,一切清零,重新装一个干净、清爽、流畅的新系统。
手机恢复出厂设置也是一样的逻辑:先把通讯录、照片、聊天记录备份好,剩下的就随便造。
下几个平时不玩的手游,装几个好奇但不敢用的 APP,卡一点、慢一点都没关系。体验完,一键恢复出厂,又是一台干干净净的新手机。

那一刻我突然觉得:人生,其实也一直在不断地重启、格式化、重装系统。
往大了说:考上大学、换一份新工作、搬到一座新城市、结婚、成为父母。。。每一次人生的重大节点,我们心里都会冒出一个念头 —— 「人生翻篇,重新开始」。这就是人生的 重装系统。把过去的美好留在备份里,把不开心、内耗、遗憾,全部当成垃圾文件删掉,轻装上阵。
往小了说:每年元旦、春节,我们都会说 —— 「新的一年,从头开始」;哪怕只是一天之内,心情不好、烦躁、沮丧,吃顿好的,再睡一觉,第二天醒来,心里那股阴霾散了,人又精神了。这就是最小单位的 恢复出厂设置。

今天开车那一路,我脑子里全是这个比喻。越想越觉得轻松,越想越觉得没什么大不了。
人生没有那么多过不去的坎,也没有那么多盯着你看的观众。你做过的尴尬事、搞砸的瞬间、放不下的包袱、内耗的情绪。。。其实都可以像系统垃圾一样,一键清理。
真正想通 「一切终将归零」 这件事,反而不是消极,而是解脱。
既然最后都要重启,那现在何必那么紧绷?何必那么在意别人的眼光?何必揪着过去不放?
人生可以随时按一下 Reset 键。 每一天,都可以是一个全新安装、干干净净、没有冗余、没有卡顿的新系统。
放下包袱,轻装上阵。往后的日子,我们都好好重启,好好做自己。
人生不过三万天 出去看看这世界
请勇敢一点 我们只活这一遍
和过去告别 拥抱更好的明天
人生的意义 该由自己来挑选
这应该是 AI 爆发的起点文章: https://openai.com/zh-Hans-CN/index/chatgpt/
可能都没想到几年后 AI 已在人类生活中扮演了非常重要的角色。
架构师的核心思维方式是其进行系统架构设计和决策的关键,除了上文提到的设计思维特点外,还包括以下几种核心思维方式。 架构师设计系统时,应善于发现问题、定义问题。 架构师设计系统时,应善于利用数据。 架构师设计系统时,要有复用思维,减少“重复造轮子”。 创新思维可以让架构始终保持生命力。 风险管理可以让架构能够抵御不确定因素带来的影响,有时这些影响甚至是致命的。 加入鸿蒙生态,共建万物互联。以下是鸿蒙应用开发常用教程。问题定义思维

数据驱动思维

复用思维
创新思维

风险管理思维
参考引用
目前仅剩 1 个位置
gemini 3.1 chat 无限额
Antigravity IDE/CLI 高优先级使用+大额 token
拼车 328
建议老谷歌账号参与,避免新号风控和降智。
除了自家的模型,还能用哪家的?
地库里经常会有流浪猫,有时候会爬到车前盖或者车顶,留下一串脚印,其实这倒也没啥,但是今早上出门的时候,发现左后轮附近有 n 撮猫毛,没养过猫,不知道是猫自己把毛弄下来的还是两只猫在这里打了架,轮胎上还有不明液体,同样也不知道是被猫尿了还是啥,觉得有点苦恼,爬车我没太所谓,但是这 n 撮猫毛还有不明液体,属实有点难顶了
点赞 + 关注 + 收藏 = 学会了 html2canvas 是一个纯前端的 JavaScript 库,能直接在浏览器里把 HTML 元素 “拍” 成 Canvas 图片。不用麻烦后端接口,就能实现网页截图、生成分享海报、保存页面快照等需求。 html2canvas 支持两种常见的安装方式,根据你的项目环境选就行: 如果你的项目用了 Webpack、Vite 等构建工具,直接用包管理器安装: 本文使用 Vite 创建 Vue3 项目,通过 Vue3 的语法来讲解。在其他框架使用 html2canvas 用法也是差不多的。 如果是简单的 HTML 项目,直接在页面里引入 CDN 链接: 先看一个最简单的例子:点击按钮,把指定的 这段代码看似简单,但第一个坑也出现了。 此时如果在“截图区”加多一个 解决方法很简单,不使用浏览器默认样式,给所有标签都加上指定样式。 html2canvas 提供了很多配置项,能帮你解决各种场景问题,这里列几个最常用的: 如果你要截的元素包含图片,而且这张图片和你的网站存在跨域情况,大概率会出现图片出空白的情况。 要解决这个问题需要2步操作。 如果想更稳妥一点,还可以给图片标签加 https://iili.io 这个图床是允许跨域的,所以我们直接在 html2canvas 里配置 生成 Canvas 后,通常需要把它转成图片文件让用户下载,这里用 html2canvas 虽然好用,但坑也不少。 前面已经提到了,如果截图里有跨域图片(比如图床的图),默认会显示空白。原因是浏览器的同源策略限制,html2canvas 无法直接读取跨域图片的像素。 解决方法: 部分 CSS 属性(如 html2canvas 是通过解析 DOM 和 CSS 手动绘制 Canvas 的,不是所有 CSS 都支持。 解决方法: 用了自定义字体(如 @font-face),截图里却变成了默认字体。 html2canvas 截图时,字体可能还没加载完,就用了默认字体渲染。 解决方法: 如果要截图的元素有滚动条,截图会包含滚动条,或者内容被截断。 解决方法: 如果页面里有 iframe,html2canvas 无法截图 iframe 里的内容。 同源策略限制,无法直接访问 iframe 内部的 DOM。 解决方法: 截图区域元素多、图片大时,生成 Canvas 会很慢,甚至浏览器卡顿。 解决方法: 直接截图 SVG 可能会变形、错位,甚至不显示。 解决方法: 截图里的元素层级和实际页面不一样,该在上面的元素跑到下面了。 html2canvas 对 解决方法: 点赞 + 关注 + 收藏 = 学会了html2canvas 简介
安装方法
1. npm /yarn 安装(推荐)
# npm 安装
npm install html2canvas
# yarn 安装
yarn add html2canvas2. CDN 引入
<script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>基础用法
div 转成 Canvas 并显示在页面上。
<template>
<div>
<!-- 要截图的区域 -->
<div ref="captureRef" style="padding: 20px; background: #f0f0f0;">
<p style="font-size: 16px; margin: 0;">随便写点什么,html2canvas 会把它变成图片~</p>
</div>
<!-- 截图按钮 -->
<button @click="handleCapture">点击截图</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import html2canvas from 'html2canvas'
// 获取要截图的 DOM 元素
const captureRef = ref(null)
// 截图函数
const handleCapture = async () => {
// 调用 html2canvas,等待生成 Canvas
const canvas = await html2canvas(captureRef.value)
// 把 Canvas 加到页面上看看效果
document.body.appendChild(canvas)
}
</script>h2,结果可能会出乎你所料。
<!-- 要截图的区域 -->
<div ref="captureRef" style="padding: 20px; background: #f0f0f0;">
<h2>雷猴</h2>
<p style="font-size: 16px; margin: 0;">随便写点什么,html2canvas 会把它变成图片~</p>
</div><h2> 标题的样式没跟着生成出来啊。。。
<template>
<div>
<!-- 要截图的区域 -->
<div
ref="captureRef"
class="capture-area"
style="padding: 20px; background: #f0f0f0;"
>
<!-- 关键样式建议写在行内,或者确保非 scoped -->
<h2 class="title">这是要截图的内容</h2>
<p style="font-size: 16px; margin: 0;">随便写点什么,html2canvas 会把它变成图片~</p>
</div>
<!-- 截图按钮 -->
<button @click="handleCapture">点击截图</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import html2canvas from 'html2canvas'
// 获取要截图的 DOM 元素
const captureRef = ref(null)
// 截图函数
const handleCapture = async () => {
// 调用 html2canvas,等待生成 Canvas
const canvas = await html2canvas(captureRef.value)
// 把 Canvas 加到页面上看看效果
document.body.appendChild(canvas)
}
</script>
<style scoped>
.capture-area {
width: 400px;
box-sizing: border-box;
border: 1px solid #ccc;
}
.title {
font-size: 24px;
font-weight: bold;
margin: 0 0 10px 0;
}
</style>常用配置选项
配置项 类型 默认值 说明 scalenumberwindow.devicePixelRatio缩放比例,默认用设备像素比,提高截图清晰度(设为 1 会模糊)。 useCORSbooleanfalse是否允许加载跨域图片,设为 true 才能正确显示跨域图片。backgroundColorstring#ffffffCanvas 背景色,设为 null 可以得到透明背景。loggingbooleanfalse是否在控制台打印日志,调试时可以设为 true 看问题。scrollXnumber0截图时的水平滚动偏移,解决页面滚动导致的内容错位。 scrollYnumber0截图时的垂直滚动偏移,同上。 
<template>
<div>
<!-- 要截图的区域 -->
<div
ref="captureRef"
class="capture-area"
style="padding: 20px; background: #f0f0f0;"
>
<!-- 关键样式建议写在行内,或者确保非 scoped -->
<h2 class="title">这是要截图的内容</h2>
<img src="https://iili.io/fcR7gSe.md.png" alt="" style="width: 140px;">
<p style="font-size: 16px; margin: 0;">随便写点什么,html2canvas 会把它变成图片~</p>
</div>
<!-- 截图按钮 -->
<button @click="handleCapture">点击截图</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import html2canvas from 'html2canvas'
// 获取要截图的 DOM 元素
const captureRef = ref(null)
// 截图函数
const handleCapture = async () => {
// 调用 html2canvas,等待生成 Canvas
const canvas = await html2canvas(captureRef.value)
// 把 Canvas 加到页面上看看效果
document.body.appendChild(canvas)
}
</script>
<style scoped>
.capture-area {
width: 400px;
box-sizing: border-box;
border: 1px solid #ccc;
}
.title {
font-size: 24px;
font-weight: bold;
margin: 0 0 10px 0;
}
</style>Access-Control-Allow-Origin: *(允许跨域)useCORS: truecrossorigin="anonymous" 属性。useCORS: true 即可。
// 省略部分代码
const canvas = await html2canvas(captureRef.value, {
useCORS: true
})高级用法:导出并下载图片
toDataURL 实现
<template>
<div>
<!-- 要截图的区域 -->
<div
ref="captureRef"
class="capture-area"
style="padding: 20px; background: #f0f0f0;"
>
<!-- 关键样式建议写在行内,或者确保非 scoped -->
<h2 class="title">这是要截图的内容</h2>
<img src="https://iili.io/fcR7gSe.md.png" alt="" style="width: 140px;">
<p style="font-size: 16px; margin: 0;">随便写点什么,html2canvas 会把它变成图片~</p>
</div>
<!-- 截图按钮 -->
<button @click="handleCapture">点击截图</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import html2canvas from 'html2canvas'
// 获取要截图的 DOM 元素
const captureRef = ref(null)
// 截图函数
const handleCapture = async () => {
// 调用 html2canvas,等待生成 Canvas
const canvas = await html2canvas(captureRef.value, { useCORS: true });
// 1. 把 Canvas 转成 PNG 格式的 base64 数据
const imgData = canvas.toDataURL('image/png');
// 2. 创建下载链接
const link = document.createElement('a');
link.download = '我的截图.png'; // 下载的文件名
link.href = imgData;
// 3. 触发点击下载
link.click();
}
</script>
<style scoped>
.capture-area {
width: 400px;
box-sizing: border-box;
border: 1px solid #ccc;
}
.title {
font-size: 24px;
font-weight: bold;
margin: 0 0 10px 0;
}
</style>常见坑点及避坑指南
跨域图片不显示或报错
Access-Control-Allow-Origin: *(允许跨域)crossorigin="anonymous" 属性useCORS: true<!-- 图片标签加 crossorigin -->
<img src="https://example.com/image.jpg" crossorigin="anonymous">CSS 样式显示异常
transform、box-shadow、复杂渐变、伪元素 ::before/::after)可能渲染不对,甚至完全不显示。自定义字体渲染失败
document.fonts.ready 即可document.getElementById('btn').addEventListener('click', async () => {
// 等待所有字体加载完成
await document.fonts.ready;
const element = document.getElementById('capture');
const canvas = await html2canvas(element);
document.body.appendChild(canvas);
});滚动条导致截图不全或有滚动条
const element = document.getElementById('capture');
// 保存原来的 overflow 样式
const originalOverflow = element.style.overflow;
// 隐藏滚动条
element.style.overflow = 'hidden';
const canvas = await html2canvas(element, {
scrollX: 0,
scrollY: 0 // 重置滚动偏移
});
// 恢复原来的样式
element.style.overflow = originalOverflow;iframe 内容无法捕获
页面元素太多导致性能差
scale(比如设为 1.5 而不是 2)display: none)SVG 元素显示异常
canvg 库辅助转换,或者手动把 SVG 转成 base64 图片// 简单的 SVG 转图片示例
const svgElement = document.querySelector('svg');
const svgData = new XMLSerializer().serializeToString(svgElement);
const img = new Image();
img.src = 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(svgData)));
// 等图片加载完后,替换原来的 SVG,再截图
img.onload = async () => {
svgElement.parentNode.replaceChild(img, svgElement);
const canvas = await html2canvas(element);
document.body.appendChild(canvas);
};z-index 层级错乱
z-index 的解析有时会出问题,尤其是元素没有显式设置 position 时。position(如 relative、absolute)z-index