需求
今天遇到一个需求,挺恶心人的,将一个在线文档页面,可以导出成为html页面查看。
看到网上有使用fs模块,通过react的ReactDOMServer.renderToStaticMarkup将组件转成html字符串,输出文件了。
但是我尝试了,发现引入的fs为空,我就愁思,这个node环境下的模块,在react项目中能用么,一想到这里,自己真的是太笨了,肯定的不适用啊。fs是node模块,除非是next.js,不然用不了。
解决
思路类似,获取页面上渲染完成的dom字符串,通过a标签下载
URL.createObjectURL(file)
const fileName = `${name}.html`;
const file = new File([htmlWithStyles], fileName, { type: 'text/html' });
const oUrl = URL.createObjectURL(file);
const a = document.createElement('a');
a.style.setProperty('display', 'none');
a.href = oUrl;
a.download = file.name;
document.body.appendChild(a);
a.click();
a.remove();
const delay = 10000;
setTimeout(() => URL.revokeObjectURL(oUrl), delay);
但是问题来了,发现下载的文件样式不存在 需要引入外部样式或者在写在style标签中
const htmlWithStyles = `
<html>
<head>
<style>${styles}</style>
</head>
<body>
<div style="display:flex; height: 100%;">
${html}
</div>
</body>
</html>
`;
笨人方法只有这样了,再高级点的,俺也不会
代码
这里的styles是外部定义的
要跟下载后的html里面的classname要对应,毕竟react项目跑起来的样式是加了很多前缀,比如这样
还有一个问题,就是使用的antd的表格,样式实在是太多了,但是还是要copy进去,不然静态页面样式就缺失了,从原本的页面里面,index.less进去,把所有的跟table相关的样式都copy过来。
所以说这个需求感觉没啥难度,但是又挺麻烦的。
封装方法
export function downHtmlFile({ html, name }) {
// 创建包含外部样式链接的 HTML 字符串
const htmlWithStyles = `
<html>
<head>
<style>${styles}</style>
</head>
<body>
<div style="display:flex; height: 100%;">
${html}
</div>
</body>
</html>
`;
const fileName = `${name}.html`;
const file = new File([htmlWithStyles], fileName, { type: 'text/html' });
const oUrl = URL.createObjectURL(file);
const a = document.createElement('a');
a.style.setProperty('display', 'none');
a.href = oUrl;
a.download = file.name;
document.body.appendChild(a);
a.click();
a.remove();
const delay = 10000;
setTimeout(() => URL.revokeObjectURL(oUrl), delay);
}
在页面代码中使用
我是class组件,函数组件用useRef就好了,思路就是通过ref获取html字符串
<div className={styles.con} ref={this.contentRef}>123</div>
this.contentRef = createRef(); // 在构造方法中定义
// 导出html文件
handleExport = name => {
const div = this.contentRef.current;
if (!div) return;
const html = div.innerHTML;
downHtmlFile({ html, name });
};