🏠

Greasy Fork is available in English.

导出微信公众号文章为PDF

在微信公众号文章页面中添加按钮,点击后导出文章为PDF格式,并显示标题、作者和时间等元信息。


安装此脚本?
提问、发表评价,或者 举报这个脚本
// ==UserScript==
// @name         导出微信公众号文章为PDF
// @namespace    https://github.com/dlzmoe/scripts
// @version      0.5
// @author       dlzmoe
// @description  在微信公众号文章页面中添加按钮,点击后导出文章为PDF格式,并显示标题、作者和时间等元信息。
// @match        https://mp.weixin.qq.com/s/*
// @grant        none
// @license      MIT
// @require      https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.9.3/html2pdf.bundle.min.js
// ==/UserScript==
(function () {
'use strict';
// 创建一个按钮
var button = document.createElement('button');
button.innerHTML = '导出为PDF';
button.style.position = 'fixed';
button.style.top = '10px';
button.style.right = '10px';
button.style.zIndex = '9999';
button.style.backgroundColor = '#4CAF50';
button.style.color = 'white';
button.style.border = 'none';
button.style.padding = '10px 20px';
button.style.fontSize = '16px';
button.style.cursor = 'pointer';
button.style.transition = 'background-color 0.3s ease'; // 添加过渡效果
document.body.appendChild(button);
// 标志位:防止连续多次点击
let isExporting = false;
// 添加加载动画
function startLoading() {
button.disabled = true; // 禁用按钮
button.style.backgroundColor = '#888'; // 变成灰色表示加载中
button.innerHTML = '正在导出...'; // 更改按钮文本为加载状态
}
// 停止加载动画
function stopLoading() {
button.disabled = false; // 启用按钮
button.style.backgroundColor = '#4CAF50'; // 恢复原始颜色
button.innerHTML = '导出为PDF'; // 恢复按钮文本
}
// 点击按钮时执行导出PDF的操作
button.addEventListener('click', function () {
if (isExporting) {
return; // 如果已经在导出过程中,则不允许再次点击
}
isExporting = true; // 设置为正在导出
startLoading(); // 启动加载动画
// 获取文章内容和标题、作者、时间等元信息
var article = document.querySelector('.rich_media_content');
var title = document.querySelector('.rich_media_title');
var author = document.querySelector('.weui-wa-hotarea'); // 文章作者
var publishTime = document.querySelector('#publish_time'); // 文章时间
if (article) {
// 创建一个容器用于添加元信息
var metaInfoDiv = document.createElement('div');
metaInfoDiv.style.marginBottom = '20px';
metaInfoDiv.style.borderBottom = '1px solid #eee';
metaInfoDiv.style.paddingBottom = '15px';
// 标题
var titleElement = document.createElement('h1');
titleElement.innerText = title ? title.innerText.trim() : '未命名文章';
titleElement.style.fontSize = '24px';
titleElement.style.marginBottom = '10px';
metaInfoDiv.appendChild(titleElement);
// 作者
if (author) {
var authorElement = document.createElement('p');
authorElement.innerText = '作者: ' + author.innerText.trim();
authorElement.style.fontSize = '14px';
authorElement.style.margin = '5px 0';
metaInfoDiv.appendChild(authorElement);
}
// 时间
if (publishTime) {
var timeElement = document.createElement('p');
timeElement.innerText = '发布时间: ' + publishTime.innerText.trim();
timeElement.style.fontSize = '14px';
timeElement.style.margin = '5px 0';
metaInfoDiv.appendChild(timeElement);
}
// 将元信息插入到文章内容的顶部
article.insertBefore(metaInfoDiv, article.firstChild);
// 添加防止图片分页的CSS样式
var style = document.createElement('style');
style.innerHTML = `
.rich_media_content img {
page-break-inside: avoid;
break-inside: avoid;
max-width: 100%;
height: auto;
}
.rich_media_content p, .rich_media_content div {
page-break-inside: avoid;
break-inside: avoid;
}
`;
document.head.appendChild(style);
// 确保所有图片加载完成
let images = article.querySelectorAll('img');
let imagePromises = [];
images.forEach(function (img) {
// 处理懒加载的图片,确保图片的真实 URL 被加载
if (img.dataset && img.dataset.src) {
img.src = img.dataset.src;
}
// 通过跨域获取图片,并将图片转换为 base64 格式
imagePromises.push(
new Promise(function (resolve) {
var imgElement = new Image();
imgElement.crossOrigin = 'Anonymous';
imgElement.src = img.src;
imgElement.onload = function () {
var canvas = document.createElement('canvas');
canvas.width = imgElement.width;
canvas.height = imgElement.height;
var ctx = canvas.getContext('2d');
ctx.drawImage(imgElement, 0, 0);
img.src = canvas.toDataURL('image/jpeg'); // 使用JPEG格式并压缩质量到70%
resolve();
};
imgElement.onerror = resolve; // 即使图片加载失败,继续处理
})
);
});
// 确保图片加载完成后再导出PDF
Promise.all(imagePromises).then(function () {
// 使用文章标题作为文件名
var fileName = title ? title.innerText.trim() + '.pdf' : 'WeChat_Article.pdf';
var opt = {
margin: 0.5,
filename: fileName,
image: {
type: 'jpeg',
quality: 1 // 降低图片质量以减小PDF体积
},
html2canvas: {
scale: 1.5, // 降低渲染比例以减小PDF体积
useCORS: true, // 允许跨域图片
logging: false, // 关闭日志
// 可以根据需要添加其他html2canvas选项
},
jsPDF: {
unit: 'in',
format: 'a4', // 使用A4格式,比letter更常用且体积可能更小
orientation: 'portrait'
},
pagebreak: {
mode: ['avoid-all', 'css', 'legacy']
} // 遵循CSS中的page-break规则
};
// 使用 html2pdf 将文章内容导出为 PDF
html2pdf().from(article).set(opt).save().then(function () {
// 导出完成后,恢复按钮状态
stopLoading();
isExporting = false; // 重置导出状态
}).catch(function (error) {
alert('导出过程中出现问题: ' + error.message);
stopLoading(); // 即使出现错误也恢复按钮状态
isExporting = false; // 重置导出状态
});
}).catch(function (error) {
alert('处理图片时出现问题: ' + error.message);
stopLoading(); // 即使出现错误也恢复按钮状态
isExporting = false; // 重置导出状态
});
} else {
alert('未找到文章内容');
stopLoading(); // 如果未找到文章内容,恢复按钮状态
isExporting = false; // 重置导出状态
}
});
})();