1.首先PhantomJS
的功能
就是提供一个浏览器环境的命令行接口,你可以把它看作一个“虚拟浏览器”,除了不能浏览,其他与正常浏览器一样。它的内核是
WebKit
引擎,不提供图形界面,只能在命令行下使用,我们可以用它完成一些特殊的用途比如。网络监测、网页截屏、无需浏览器的
Web 测试、等等
2. 详细的功能可见官网https://phantomjs.org
3.本项目demo主要用到的api
https://phantomjs.org/api/webpage/property/paper-size.html
4 我们要实现的效果如下,当访问url时
可以看到生成的pdf对样式和图片都支持的很好
大概的逻辑流程如下:
首先安装koa相应的依赖和phantom
cnpm i koa koa-views ejs uuid koa-static koa-body phantom
1.搭建http服务器
基本koa配置
const Koa = require('koa');
const path = require('path');
const views = require('koa-views');
const phantom = require('phantom');
const uuid = require('uuid');
const fs = require('fs');
const static = require('koa-static');
const body = require('koa-body');
const app = new Koa();
app.use(body()); //解析body中间件
app.use(views(path.join(__dirname, 'views'), { //设置模板引擎
extension: 'ejs'
}))
app.listen(8080);
//监听端口
ejs模板响应
app.use(async (ctx, next) => { //请求获取html
const url = ctx.url;
if (url === '/ejs2html') {
const data = ctx.request.body; //获取请求的参数
await ctx.render('index', data) //渲染
}
await next();
})
转pdf的请求处理
app.use(async (ctx, next) => { //获取pdf
const url = ctx.url;
if (url === '/getpdf') {
const data = await transformPdf();
ctx.set({
'Content-Type':
'application/pdf'
})
ctx.body = fs.createReadStream(data.data.file); //返回pdf
}
})
2.实现 transformPdf方法
创建实例
async function transformPdf() {
let ph = await phantom.create();
let page = await ph.createPage();
设置phantom请求ejs模板页面时的相关参数(这里的
date
可以在请求时动态传入,因为是demo
就写死了)
var settings = { //设置请求相关的配置
operation: "POST",
encoding: "utf8",
headers: {
"Content-Type": "application/json"
},
data: JSON.stringify({ name: "转pdf啦!!!" }) //请求主体
};
请求页面
url = "http://localhost:8080/ejs2html"; // 本地注册的路由
let status = await page.open(url, settings); // 打开ejs模板的页面
- 如果请求成功,设置pdf页面的相关属性,然后返回存储路径
if (status == "success") {
let filename = path.join(__dirname, 'pdf', uuid.v4() + '.pdf'); // 临时文件的下载目的路径
page.property('viewportSize', { width: 600, height: 600 }); //设置pdf的页面大小
page.property('paperSize', { //设置页面相关的属性
format: 'A4',
margin: {
top: '30px'
},
footer: {
height: "30px",
contents: ph.callback(function (pageNum, numPages) {
return "<div align='center'><span>P." + pageNum + " of " + numPages + "</span></div>";
})
}
});
await page.render(filename); // 将html转换为pdf 并且保存到当前filename设置的目录下
ph.exit();
return { msg: '', data: { file: filename } };
} else {
return { msg: 'error', data: {} };
}
}
- 目录结构如下
- ejs模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1 style="color: aqua;"><%= name%></h1>
<img src="/timg.jpg" alt="青蛙">
</body>
</html>
- 注意事项
在转pdf时ejs模板开发如果使用到flex之类,请添加-webkit前缀,否则不生效
还有如果为了防止内容内分页可以在加page-break-inside: avoid;
css样式可以防止内容被分页