需求
今天遇到一个需求,挺恶心人的,将一个在线文档页面,可以导出成为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 });};