Angular4传HTML至Linux PHP端用wkhtmltopdf生成PDF样式失效如何解决
嘿,我之前在做类似的Angular转PDF需求时,也碰到过wkhtmltopdf样式丢失的坑,结合你的场景,给你几个针对性的解决思路:
这是最常见的解决方案,因为wkhtmltopdf对外部样式表的支持很“挑剔”,而且Angular的组件样式默认是封装的,你直接取innerHTML根本拿不到组件的样式。
你可以在获取HTML之前,把需要的样式(组件样式、全局样式)塞进一个<style>标签,插入到目标元素的头部:
public getPdf() { // 先插入内联样式 const styleTag = document.createElement('style'); // 这里可以写你需要的所有CSS,比如组件的样式、全局样式 styleTag.textContent = ` .pdf-content { font-size: 14px; color: #333; padding: 20px; } .pdf-title { font-size: 20px; font-weight: bold; margin-bottom: 15px; } /* 其他需要的样式... */ `; this.pdfEl.insertBefore(styleTag, this.pdfEl.firstChild); // 再获取包含样式的完整HTML文档 const html = ` <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> </head> <body> ${this.pdfEl.innerHTML} </body> </html> `; this.rest.post( '/pdf', { html }, { headers: new Headers(), responseType: ResponseContentType.Blob } ).subscribe((value) => { this.url = URL.createObjectURL(value.blob()); open(this.url); }); }
注意:如果你的组件用了默认的ViewEncapsulation.Emulated,组件样式会加随机前缀,直接复制的话可能不生效。这时候要么把需要的样式改成全局样式,要么手动去掉前缀,或者给组件设置ViewEncapsulation.None(注意避免样式污染全局)。
如果你的样式里用到了图片、字体等外部资源,一定要把路径改成服务器能访问的绝对路径,比如https://your-domain.com/assets/fonts/roboto.ttf,而不是相对路径../assets/fonts/roboto.ttf。因为wkhtmltopdf是在Linux服务器上运行的,它的相对路径是相对于服务器的工作目录,不是前端页面的路径。
另外,你可以在wkhtmltopdf的PHP封装里添加--enable-local-file-access参数,允许它加载服务器本地的资源文件。
wkhtmltopdf对HTML的完整性要求很高,如果你只传了部分DOM的innerHTML(比如只有<div>内容),它可能无法正确解析样式。所以一定要把HTML包裹成完整的文档结构,就像上面代码里那样,加上<!DOCTYPE html>、<html>、<head>、<body>标签。
有时候默认参数会导致样式失效,你可以在PHP端的wkhtmltopdf封装里添加这些参数试试:
--disable-smart-shrinking:防止自动缩放打乱布局和样式--page-size A4:指定页面大小,避免内容溢出--enable-javascript:如果你的样式依赖JS动态生成(尽量避免这种情况,wkhtmltopdf对JS支持有限)
你可以先把前端生成的HTML保存成一个静态.html文件,然后在服务器上用wkhtmltopdf命令行直接生成PDF:
wkhtmltopdf input.html output.pdf
如果这个静态PDF有样式,说明问题出在前端发送HTML的过程中;如果还是没样式,就专注调整HTML结构和样式本身,或者wkhtmltopdf的参数。
内容的提问来源于stack exchange,提问作者The Outstanding Question Asker

