当前位置: 首页 > news >正文

html2canvas + jspdf 纯前端HTML导出PDF的实现与问题

前言

        这几天接到一个需求,富文本编辑器的内容不仅要展示出来,还要实现展示的内容导出pdf文件。一开始导出pdf的功能是由后端来做的,然后发现对于宽度太大的图片,导出的pdf文件里部分图片内容被遮盖了,但在前端是正常显示的,只因为class样式后端无法解析。然后,后端开发人员就嫌麻烦,让前端来实现导出pdf的功能。。。

html2canvas(V1.4.1)

         html2canvas 用于将 html 元素渲染成图像,可以将整个页面或特定区域以图像形式进行捕获。这对于将复杂的 html 结构转换为 PDF 格式非常有用,因为它可以捕获 html 中的样式、布局和图像等细节。

        官网:https://html2canvas.hertzen.com/

引用

npm install html2canvas@1.4.1 --save
或
yarn add html2canvas@1.4.1
或
<script src="https://html2canvas.hertzen.com/dist/html2canvas.js"></script>

示例

<template><div id="pdfBody" style="margin: 30px;"><input class="test_input" type="text" autocomplete="off" placeholder="输入框111"/><input class="test_btn" id="testBtn" type="button" value="按钮"/></div>
</template><script>import html2canvas from "@/utils/htmlToPdf/html2canvas.min";export default {name: "Test",mounted() {document.getElementById('testBtn').addEventListener('click', () => {this.canvasTest();});},methods: {createCanvas(dom) {html2canvas(dom, {useCORS: true, //允许跨域scale: 2, //按比例增加分辨率dpi: 200, //将分辨率提高到特定的DPI(每英寸点数)ignoreElements: (e) => {//过滤head、body等无用的标签元素return !(e.contains(dom) || dom.contains(e) || e.tagName === 'STYLE' || e.tagName === 'LINK');},onclone: (doc) => {//Scoped CSS无法直接应用,需要手动处理let inputDocArr = doc.getElementsByClassName('test_input');[].forEach.call(inputDocArr, inputDoc => {inputDoc.style.height = '36px';inputDoc.style.lineheight = '36px';inputDoc.style.width = '200px';inputDoc.style.margin = '20px';inputDoc.style.borderRadius = '5px';inputDoc.style.border = '1px solid #DCDFE6';});let btnDocArr = doc.getElementsByClassName('test_btn');[].forEach.call(btnDocArr, btnDoc => {btnDoc.style.color = '#FFFFFF';btnDoc.style.backgroundColor = '#1890ff';btnDoc.style.border = '1px solid #1890ff';btnDoc.style.height = '36px';btnDoc.style.width = '80px';btnDoc.style.borderRadius = '20px';});}}).then(canvas => {dom.appendChild(canvas);}).finally(() => {console.log('create canvas finish!');});},canvasTest() {let pdfBody = document.getElementById('pdfBody');this.createCanvas(pdfBody);}}}
</script><style scoped>.test_input {height: 36px;line-height: 36px;width: 200px;margin: 20px;border-radius: 5px;border: 1px solid #DCDFE6;}.test_input:focus {border: 1px solid #1890ff;outline: none;}.test_btn {color: #FFFFFF;background-color: #1890ff;border: 1px solid #1890ff;height: 36px;width: 80px;border-radius: 20px;cursor: pointer;}
</style>

 配置项

        如果想隐藏某个元素不让其显示出来,参考以下几种方案:

        1、元素标签添加 data-html2canvas-ignore 属性,示例如下:

        2、配置项中添加 ignoreElements 属性,手动过滤某个元素,示例如上代码;

        3、配置项中添加 onclone 属性,手动处理某个元素的显示与隐藏,即:element.style.display = 'hidden'。

jsPDF(V1.5.3)

         jsPDF 是一个 PDF 生成库,它允许你通过 JavaScript 代码创建和编辑 PDF 文档。

        官网:https://github.com/parallax/jsPDF

引用

npm install jsPDF@1.5.3 --save
或
yarn add jsPDF@1.5.3
或
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.min.js"></script>

 示例

<template><div id="pdfBody" style="margin: 30px;"><h3>测试创建pdf文件!</h3><input id="testPdf" type="button" value="pdf测试"/></div>
</template><script>import jsPDF from "@/utils/htmlToPdf/jspdf.min";export default {name: "Test",mounted() {document.getElementById('testPdf').addEventListener('click', () => {this.pdfTest();});},methods: {pdfTest() {let doc = new jsPDF({orientation: 'p',unit: 'mm',format: 'a4'});doc.text("Hello world!", 10, 10);doc.save("测试.pdf");}}}
</script>

设置中文字体

        设置英文内容是正常显示的,假若内容包含中文,会发现pdf文件里的内容显示乱码,如下图所示:

let doc = new jsPDF({orientation: 'p',    unit: 'mm',format: 'a4'
});
doc.text("pdf文件测试!", 10, 10);
doc.save("测试.pdf");

        解决这一问题,可以使用 jsPDF 提供的 setFont(font) 方法,具体操作如下:

        1、网上下载一个支持中文的字体tff文件,或者拷贝一份本地 window/font/ 路径下的字体文件(ps:有的字体不支持);

        2、从GitHub上下载jsPDF源码,然后打开fontconverter目录下的fontconverter.html文件;

        3、选择本地的tff文件,点击“Create”按钮,会生成一个js文件;

        4、一般情况下,生成的js文件直接引入页面使用会报错,需要手动处理生成新的js文件;

        默认生成的js文件内容如下:

(function (jsPDFAPI) {var font = "XXXXXX";var callAddFont = function () {this.addFileToVFS("simfang.ttf", font);this.addFont("simfang.ttf", "simfang", "normal");
};
jsPDFAPI.events.push(['addFonts', callAddFont])})(jsPDF.API);

        然后复制一份js文件,编辑内容如下格式:

export function addfont(pdf) {let font = 'XXXXXX';pdf.addFileToVFS('simfang.ttf', font);pdf.addFont('simfang.ttf', 'simfang', 'normal');
}

        5、将处理好的新的js文件放入项目中,然后在页面中引用,并设置字体。

<template><div id="pdfBody" style="margin: 30px;"><h3>测试创建pdf文件!</h3><input id="testPdf" type="button" value="pdf测试"/></div>
</template><script>import jsPDF from "@/utils/htmlToPdf/jspdf.min";import {addfont} from '@/utils/htmlToPdf/simfang';export default {name: "Test",mounted() {document.getElementById('testPdf').addEventListener('click', () => {this.pdfTest();});},methods: {pdfTest() {let doc = new jsPDF({orientation: 'p',unit: 'mm',format: 'a4'});//设置中文字体addfont(doc);doc.setFont('simfang');doc.text("pdf文件测试撒大大大飒飒热通过如果还有就要让他阿松大尔特瑞特好几年,是否然后他又就很尴尬发射任务给他人用不上,二条天皇已经不是v堵塞惹我实在是肉体和set一年德国必须色让他管很多人把!", 10, 10);doc.save("测试.pdf");}}}
</script>

解决jsPDF文本不自动换行问题

        中文乱码问题解决了,然后新的问题又出现了,文本不自动换行。解决方案参考如下:

        1、使用 splitTextToSize() 方法:

let doc = new jsPDF({orientation: 'p',unit: 'mm',format: 'a4'    
});
//设置中文字体
addfont(doc);
doc.setFont('simfang');
let con = "pdf文件测试撒大大大飒飒热通过如果还有就要让他阿松大尔特瑞特好几年,是否然后他又就很尴尬发射任务给他人用不上,二条天皇已经不是v堵塞惹我实在是肉体和set一年德国必须色让他管很多人把!";
let splitCon = doc.splitTextToSize(con, 190);
console.log('splitCon',splitCon)
doc.text(splitCon, 10, 10);
doc.save("测试.pdf");

        2、text() 方法参数添加选项 maxWidth :

let doc = new jsPDF({orientation: 'p',unit: 'mm',format: 'a4'
});
//设置中文字体
addfont(doc);
doc.setFont('simfang');
let con = "pdf文件测试撒大大大飒飒热通过如果还有就要让他阿松大尔特瑞特好几年,是否然后他又就很尴尬发射任务给他人用不上,二条天皇已经不是v堵塞惹我实在是肉体和set一年德国必须色让他管很多人把!";
doc.text(con, 10, 10, {maxWidth: 190
});
doc.save("测试.pdf");

jsPDF 库 API

        文档地址:https://artskydj.github.io/jsPDF/docs/index.html

        以下是常用API,仅供参考:

方法说明
var doc = new jsPDF(orientation, unit, format, compress);

创建新文档:

orientation:"l"(横向)、"p"(纵向);

unit:"pt"、"mm"(默认)、"cm"、"m"、"in" or "px";

format:"a3"、"a4(默认)"、"a5"、"letter"、"legal"等

doc.addPage()添加一个空白页
doc.setPage(pageNumber)切换到第几个页面操作
doc.internal.getNumberOfPages()获取总页面数
doc.text(text, x, y, options);

页面中添加文本:

text:文本内容;

x:距离页面左边的距离;

y:距离页面上边的距离;

options:可选参数配置

doc.setFont(fontName, fontStyle)

页面文本设置字体:

fontName:字体名称;

fontStyle:字体风格,如"加粗"

doc.setFontSize(size);设置字体大小
doc.setTextColor(ch1, ch2, ch3, ch4);设置文本颜色,可以是颜色码或rgb值
doc.addImage(imageData,format, x, y, width, height)

在 PDF 文件中添加一个图像:

imageData:图像的数据;

format:图像的类型,如"JPEG";

x、y:分别表示图像左上角的坐标;

width:图像的宽度;

height:图像的高度

doc.save(filename)生成指定文件名的PDF文件

html2canvas + jsPDF

        jsPDF 与 html2canvas 结合使用,可以将 html 元素渲染成图像,然后将图像插入到 jsPDF 创建的 PDF 文档中。

示例

import html2canvas from "@/utils/htmlToPdf/html2canvas.min";
import jsPDF from "@/utils/htmlToPdf/jspdf.min";
import {addfont} from '@/utils/htmlToPdf/simfang';
import {Loading} from "element-ui";export function downloadPdf(title, dom) {let reqLoading = Loading.service({fullscreen: true,text: '正在生成PDF文件......',spinner: 'el-icon-loading',background: 'rgba(0,0,0,0.5)'});html2canvas(dom, {useCORS: true, //允许跨域scale: 2, //按比例增加分辨率dpi: 200, //将分辨率提高到特定的DPI(每英寸点数)ignoreElements: (e) => {return !(e.contains(dom) || dom.contains(e) || e.tagName === 'STYLE' || e.tagName === 'LINK');}}).then(canvas => {// dom.appendChild(canvas);// 新建JsPDF对象let PDF = new jsPDF({orientation: 'p', //参数: l:横向  p:纵向unit: 'mm', //参数:测量单位("pt","mm", "cm", "m", "in" or "px")format: 'a4', //A4纸});let ctx = canvas.getContext('2d');let a4w = 190;let a4h = 272; //A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277,底部留5mm的页码显示位置,所以高度为272mm。let imgHeight = Math.floor(a4h * canvas.width / a4w) - 2; //按A4显示比例换算一页图像的像素高度let renderedHeight = 0;//计算总页数let pageCount = Math.ceil(canvas.height / imgHeight);let page = document.createElement("canvas");page.width = canvas.width;//设置中文字体addfont(PDF);PDF.setFont('simfang');while (renderedHeight < canvas.height) {page.height = Math.min(imgHeight, canvas.height - renderedHeight); //可能内容不足一页//用getImageData剪裁指定区域,并画到前面创建的canvas对象中page.getContext('2d').putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight)), 0, 0);//canvas转图片数据保留10mm边距PDF.addImage(page.toDataURL('image/jpeg', 1), 'JPEG', 10, 10, a4w, Math.min(a4h, a4w * page.height / page.width));renderedHeight += imgHeight;//计算当前页及文字let pageNumberText = '第' + (renderedHeight / imgHeight) + '页/共' + pageCount + '页';//设置文字大小PDF.setFontSize(4);//设置文字颜色PDF.setTextColor('#999');//在页脚添加页码PDF.text(pageNumberText, ((a4w + 8) / 2), (a4h + 16));//判断是否分页,如果后面还有内容,添加一个空页if (renderedHeight < canvas.height) {PDF.addPage();}}PDF.save(title + ".pdf");}).finally(() => {if (reqLoading) {reqLoading.close();}});
}

常见问题

截取的图片显示空白

1、跨域问题

        html2canvas 默认是不支持跨域图片的,对于跨域的图片默认是无法截取进去的,需要开启跨域配置:

  1. 将图片转成 base64 形式;
  2. 设置配置项 allowTaint: true 或 useCORS: true;
  3. img 标签中添加 crossOrigin="anonymous";
  4. 图片服务器配置 Access-Control-Allow-Origin: *

2、图片未加载完成

        若图片未加载完成,此时截取的也是空白,解决方法就是设置延时一定事件后处理,或图片添加 load 事件,等图片加载完在进行截图。

3、需要截图的dom元素太多

        若出现前面内容都正常截取,后面内容出现空白,大概率就是dom元素太多了。本人就碰到这种情况,即使延时10秒后截取,后面的部分还是空白,没办法,最后只能后端实现导出pdf功能了。。。

截图后部分css效果未正常显示

1、部分css样式 html2canvas 不支持

        html2canvas 无法支持全部的css样式,关于支持哪些css样式或不支持哪些css样式,可以参考文档:https://html2canvas.hertzen.com/features

2、scoped 作用域的css无法应用

        在vue中,为了避免css样式的交叉污染,都会使用 scoped 作用域的css样式,但是该作用域下的css样式无法在 html2canvas 中使用,解决方案可以在 onclone 配置项中过滤元素手动处理样式(详情可参考上述示例)

        其他的问题可以参考博文:https://www.cnblogs.com/padding1015/p/9225517.html

总结

        使用 html2canvas + jsPDF 纯前端导出pdf的方式还是有很多问题的,一般情况下都是后端进行文件的导出,前端配合解决样式问题。

        另外我看还有使用 dom-to-image 或 modern-screenshot 的,不知道效果怎么样,有时间可以试一下。

相关文章:

html2canvas + jspdf 纯前端HTML导出PDF的实现与问题

前言 这几天接到一个需求&#xff0c;富文本编辑器的内容不仅要展示出来&#xff0c;还要实现展示的内容导出pdf文件。一开始导出pdf的功能是由后端来做的&#xff0c;然后发现对于宽度太大的图片&#xff0c;导出的pdf文件里部分图片内容被遮盖了&#xff0c;但在前端是正常显…...

【JVM】JVM调优练习-随笔

JVM实战笔记-随笔 前言字节码如何查看字节码文件jclasslibJavapArthasArthurs监控面板Arthus查看字节码信息 内存调优内存溢出的常见场景解决内存溢出发现问题Top命令VisualVMArthas使用案例 Prometheus Grafana案例 堆内存情况对比内存泄漏的原因:代码中的内存泄漏并发请求问…...

如何解决 CentOS 7 官方 yum 仓库无法使用

一、背景介绍 编译基于 CentOS 7.6.1810 镜像的 Dockerfile 过程中,执行 yum install 指令时,遇到了错误:Could not resolve host: mirrorlist.centos.org; Unknown error。 二、原因分析 官方停止维护 CentOS 7。该系统内置的 yum.repo 所使用的域名 mirrorlist.centos.o…...

分布式唯一id的7种方案

背景 为什么需要使用分布式唯一id&#xff1f; 如果我们的系统是单体的&#xff0c;数据库是单库&#xff0c;那无所谓&#xff0c;怎么搞都行。 但是如果系统是多系统&#xff0c;如果id是和业务相关&#xff0c;由各个系统生成的情况下&#xff0c;那每个主机生成的主键id就…...

嵌入式物联网在医疗行业中的应用——案例分析

作者主页: 知孤云出岫 目录 嵌入式物联网在医疗行业中的应用——案例分析引言1. 智能病房监控1.1 实时患者监控系统 2. 智能医疗设备管理2.1 设备使用跟踪与维护 3. 智能药物管理3.1 药物分配与跟踪 4. 智能远程医疗4.1 远程患者监控与诊断 总结 嵌入式物联网在医疗行业中的应…...

C语言 底层逻辑详细阐述指针(一)万字讲解 #指针是什么? #指针和指针类型 #指针的解引用 #野指针 #指针的运算 #指针和数组 #二级指针 #指针数组

文章目录 前言 序1&#xff1a;什么是内存&#xff1f; 序2&#xff1a;地址是怎么产生的&#xff1f; 一、指针是什么 1、指针变量的创建及其意义&#xff1a; 2、指针变量的大小 二、指针的解引用 三、指针类型存在的意义 四、野指针 1、什么是野指针 2、野指针的成因 a、指…...

【人工智能大模型】文心一言介绍以及基本使用指令

目录 一、产品背景与技术基础 二、主要功能与特点 基本用法 指令的使用 注意事项 文心一言&#xff08;ERNIE Bot&#xff09;是百度基于其文心大模型技术推出的生成式AI产品。以下是对文心一言的详细介绍&#xff1a; 一、产品背景与技术基础 技术背景&#xff1a;百度…...

AI绘画入门实践|Midjourney 的模型版本

模型分类 Midjourney 的模型主要分为2大类&#xff1a; 默认模型&#xff1a;目前包括&#xff1a;V1, V2, V3, V4, V5.0, V5.1, V5.2, V6 NIJI模型&#xff1a;目前包括&#xff1a;NIJI V4, NIJI V5, NIJI V6 模型切换 你在服务器输入框中输入 /settings&#xff1a; 回车后…...

Web3时代的教育技术革新:智能合约在学习管理中的应用

随着区块链技术的发展和普及&#xff0c;Web3时代正在为教育技术带来前所未有的革新和机遇。智能合约作为区块链技术的核心应用之一&#xff0c;不仅在金融和供应链管理等领域展示了其巨大的潜力&#xff0c;也在教育领域中逐渐探索和应用。本文将探讨智能合约在学习管理中的具…...

云计算实训室的核心功能有哪些?

在当今数字化转型浪潮中&#xff0c;云计算技术作为推动行业变革的关键力量&#xff0c;其重要性不言而喻。唯众&#xff0c;作为教育实训解决方案的领先者&#xff0c;深刻洞察到市场对云计算技能人才的迫切需求&#xff0c;精心打造了云计算实训室。这一实训平台不仅集成了先…...

芯科科技第五届物联网开发者大会走进世界各地,巡回开启注册

中国&#xff0c;北京 – 2024年7月18日 – 致力于以安全、智能无线连接技术&#xff0c;建立更互联世界的全球领导厂商Silicon Labs&#xff08;亦称“芯科科技”&#xff0c;NASDAQ&#xff1a;SLAB&#xff09;今日宣布&#xff0c;其2024年Works With开发者大会现正开放注册…...

Python创建Excel表和读取Excel表的基础操作

下载openpyxl第三方库 winr打开命令行输入cmd 这个如果不行可以试试其他方法&#xff0c;在运行Python代码的软件里也有直接下载的地方&#xff0c;可以上网搜索 创建Excel表 示例代码&#xff1a;最后要记得保存&#xff0c;可以加一句提示语句。 import openpyxl lst[100,…...

JVM(day2)经典垃圾收集器

经典垃圾收集器 Serial收集 使用一个处理器或一条收集线程去完成垃圾收集工作&#xff0c;更重要的是强调在它进行垃圾收集时&#xff0c;必须暂停其他所有工作线程&#xff0c;直到它收集结束。 ParNew收集器 ParNew 收集器除了支持多线程并行收集之外&#xff0c;其他与 …...

华为od机试真题 — 分披萨(Python)

题目描述 “吃货”和“馋嘴”两人到披萨店点了一份铁盘(圆形)披萨&#xff0c;并嘱咐店员将披萨按放射状切成大小相同的偶数个小块。 但是粗心服务员将披萨切成了每块大小都完全不同奇数块&#xff0c;且肉眼能分辨出大小。 由于两人都想吃到最多的披萨&#xff0c;他们商量…...

ubuntu22.04 安装boost

下载boost压缩包&#xff0c;我这里上传了一份1_81_0版本tar -xzvf boost_1_81_0.tar.gzcd boost_1_81_0/sudo apt install build-essential g autotools-dev libicu-dev libbz2-dev -ysudo ./bootstrap.sh --prefix/usr/./b2sudo ./b2 install 上述7步完成后&#xff0c;相关…...

基于JAVA+SpringBoot+uniapp的心理小程序(小程序版本)

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、SpringCloud、Layui、Echarts图表、Nodejs、爬…...

C语言 ——— 输入两个正整数,求出最小公倍数

目录 何为最小公倍数 题目要求 代码实现 方法一&#xff1a;暴力求解法&#xff08;不推荐&#xff09; 方法二&#xff1a;递乘试摸法&#xff08;推荐&#xff09; 何为最小公倍数 最小公倍数是指两个或者多个正整数&#xff08;除了0以外&#xff09;的最小的公共倍数…...

Langchain 对pdf,word,txt等不同文件的加载解析

项目中遇到各种数据资源想要加载近langchain构建本地知识ai系统&#xff0c;怎么加载对应的文件格式呢&#xff0c;一起研究下 引入Langchain from langchain.document_loaders import UnstructuredWordDocumentLoader,PyPDFium2Loader,DirectoryLoader,PyPDFLoader,TextLoad…...

BL201分布式I/O耦合器连接Profinet网络

钡铼技术的BL201分布式I/O耦合器是一个用于Profinet网络的设备&#xff0c;用于连接远程输入/输出&#xff08;I/O&#xff09;设备到控制系统&#xff0c;如可编程逻辑控制器&#xff08;PLC&#xff09;&#xff0c;能够实现分布式的I/O连接和通信。 它支持标准Profinet IO …...

Pycharm 报错 Environment location directory is not empty 解

删除项目中ven文件夹&#xff08;已存在的&#xff09;&#xff0c;然后再添加新的ven虚拟环境就可以了...

第三篇:变量

一.变量 1.变量的创建 &#xff08;1&#xff09;语法格式&#xff1a;data_type name; 补充&#xff1a;其中“data_type"是数据类型&#xff0c;”name"是变量名&#xff0c;变量名根据需求随意取即可&#xff0c;但尽量取得有意义 例如&#xff1a;int age 10;(创…...

AI编程智能体评估平台CodingAgentExplorer:从原理到实践的系统评测指南

1. 项目概述&#xff1a;一个探索智能体编码能力的开源工具最近在GitHub上闲逛&#xff0c;发现了一个挺有意思的项目&#xff1a;tndata/CodingAgentExplorer。光看名字&#xff0c;你可能会觉得这又是一个“AI写代码”的工具&#xff0c;市面上这类工具已经多如牛毛了。但当我…...

Arm CoreSight SoC-400 CTI架构与调试技术详解

1. Arm CoreSight SoC-400 CTI架构概述在复杂的多核SoC开发过程中&#xff0c;高效的调试机制是确保系统可靠性的关键。Arm CoreSight架构中的Cross Trigger Interface&#xff08;CTI&#xff09;模块作为硬件级调试基础设施&#xff0c;实现了处理器核之间的精确事件同步。So…...

构建更优Godot MCP:AI助手与游戏开发工作流深度集成方案

1. 项目概述&#xff1a;为什么我们需要一个更好的Godot MCP&#xff1f;如果你是一个长期使用Godot引擎的开发者&#xff0c;尤其是当你尝试将AI能力&#xff0c;比如大型语言模型&#xff08;LLM&#xff09;&#xff0c;集成到你的游戏开发工作流中时&#xff0c;你很可能听…...

2026年最佳同城小程序推荐榜单,助你高效解锁本地生活

本文围绕同城小程序的技术架构、功能覆盖及实际应用效果展开深度解析&#xff0c;系统梳理了当前市场上的主流工具如何助力用户高效解锁本地生活服务。通过对多项核心指标的横向测评与案例分析&#xff0c;重点探讨了同城小程序在资源匹配效率、数据安全机制及生态扩展性方面的…...

为OpenClaw智能体工作流配置Taotoken作为统一的模型服务后端

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 为OpenClaw智能体工作流配置Taotoken作为统一的模型服务后端 对于使用OpenClaw框架构建AI智能体的开发者而言&#xff0c;一个稳定…...

LinkSwift:如何让网盘下载从龟速到光速?这款工具给出了答案

LinkSwift&#xff1a;如何让网盘下载从龟速到光速&#xff1f;这款工具给出了答案 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国…...

Windows与Office终极激活指南:KMS_VL_ALL_AIO智能脚本免费解决方案

Windows与Office终极激活指南&#xff1a;KMS_VL_ALL_AIO智能脚本免费解决方案 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO 还在为系统激活烦恼吗&#xff1f;KMS_VL_ALL_AIO智能激活脚本为您…...

Windows Cleaner终极指南:快速免费解决C盘爆红问题

Windows Cleaner终极指南&#xff1a;快速免费解决C盘爆红问题 【免费下载链接】WindowsCleaner Windows Cleaner——专治C盘爆红及各种不服&#xff01; 项目地址: https://gitcode.com/gh_mirrors/wi/WindowsCleaner 你是否曾因C盘爆红而焦急万分&#xff1f;系统运行…...

3分钟快速解密QMC加密音乐:QMCDecoder完整使用指南

3分钟快速解密QMC加密音乐&#xff1a;QMCDecoder完整使用指南 【免费下载链接】qmc-decoder Fastest & best convert qmc 2 mp3 | flac tools 项目地址: https://gitcode.com/gh_mirrors/qm/qmc-decoder 你是否遇到过QQ音乐下载的歌曲只能在特定播放器里播放&#…...