`;
printDom.push(flexItemDom);
return printDom;
// 执行打印
const getPrintDom = (data) => {
const printDom = getPrintItemDom(data);
let printDomStr = printDom.join(''); // 最终打印的结构及样式
const iframe = document.createElement('IFRAME'); // 创建iframe
let doc = null; // 打印的文档
iframe.setAttribute('style', 'width:0;height:0;left:0;top:0'); // 设置iframe的样式
// iframe.setAttribute('style', 'width:800px;height:900px;left:0;top:0;z-index:2000;background:gold;'); // 设置iframe的样式--调试的时候换成这个
document.body.appendChild(iframe); // 将iframe追加进body
doc = iframe.contentWindow.document; // 获取iframe的文档
doc.open(); // 开始写入iframe
doc.write(printDomStr); // 写入打印的dom数据
doc.close(); // 结束写入,关闭文档
iframe.contentWindow.focus(); // 使iframe作为打印的容器
iframe.contentWindow.print(); // 调起打印
setTimeout(() => {
document.body.removeChild(iframe); // 删除iframe
},200);
使用打印方法的时候数据传参是有参考之前的hiprint,总体大的参数是数组类型,参数结构如下:
const renderData = [
displayInBlock: {
begin: boolean // end同行的最后一个元素,begin同行的第一个元素
} // 是否和某个打印的数据在同一行展示 非必传
type: 'table', // 打印的元素的类型,是domstr/table/descriptions,目前只定义了这三种展示样式,在最后有case,具体的printElement的参数都和type有关
printElement: {
columns: columnsData, // 表格类型必传,表头
data: tableData: // 表格类型必传,表格数据
domStr: htmlStr // html字符串 domstr类型必传
renderStyle: string // 额外的一些渲染样式,非必传
columnsData的格式:
const columnsData = [
title: '性别', // 表头
width: '25%', // 列宽
field: 'sex', // 对应的数据字段的key
formatter: (field, value, row) => {} // 自定义展示函数,若不写,则默认展示字段的值
具体使用case参考:
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<button id='actionBtn'>打印</button>
</body>
<script>
// 打印的数据
// 表头
const testTableColumns = [
title: '账号',
width: '25%',
field: 'id',
title: '姓名',
width: '25%',
field: 'name',
formatter: (field, value, row) => {
const returnVal = row.sex === 0 ? `${value}先生` : `${value}女士`;
return returnVal;
title: '性别',
width: '25%',
field: 'sex',
formatter: (field, value, row) => {
let domStr = `<p style='color: red'>女</p>`;
if (value === 0) {
domStr = `<p>男</p>`
return domStr;
title: '年龄',
width: '25%',
field: 'age'
// 表数据
const testTableData = [
id: '001',
name: 'Andy',
sex: 1,
age: '22'
id: '002',
name: 'Bob',
sex: 0,
age: '23'
id: '003',
name: 'Tom',
sex: 0,
age: '20'
// 根据打印的数据类型组装dom
const getPrintItemDom = (data) => {
if (!data || data.length === 0) {
return [];
const printDom = [];
data.forEach((itemObj) => {
if (itemObj.printElement && itemObj.printElement.children) {
const childrenDomArr = getPrintItemDom(itemObj.printElement.children);
const parentTitle = itemObj.title ? `<p style="font-weight:bold;font-size:12px;margin:0;line-height: 24px">${itemObj.title}</p>` : '';
const childrenDomStr = `${parentTitle}<div style=${itemObj.renderStyle || ''}>${childrenDomArr.join('')}</div>`;
printDom.push(childrenDomStr);
} else {
let itemDom = itemObj.title ? `<p style="font-weight:bold;font-size:12px;margin:0;line-height: 24px">${itemObj.title}</p>` : '';
if (itemObj.printElement && itemObj.printElement.data && itemObj.printElement.data.length) {
switch (itemObj.type) {
case 'domstr':
itemDom += `<div>${itemObj.printElement.data}</div>`;
break;
case 'table':
const tableHeadTh = itemObj.printElement.columns.map(item => `<th style='border:1px solid #000;border-top:none;border-left:none;width:${item.width}'>${item.title}</th>`); // 表头
const tableData = itemObj.printElement.data.map((item) => {
const itemTd = itemObj.printElement.columns.map((citem) => {
return `<td style='border:1px solid #000;border-top:none;border-left:none;width:${citem.width};word-break:break-all'>${citem.formatter ? citem.formatter(citem.field, item[citem.field], item) : item[citem.field]}</td>`;
const itemTr = `<tr>${itemTd.join('')}</tr>`;
return itemTr;
}); // 表数据
itemDom += `<table style='font-size:12px;border:1px solid #000;border-bottom:none;border-right:none;text-align:center;' cellspacing='0'>
${tableHeadTh.join('')}
${tableData.join('')}
</table>`;
break;
case 'descriptions':
const listColumn = itemObj.printElement.columns || 1; // 数值,一行展示几列
* [{label: '账号', value: 'a123',... }]
const totalNum = itemObj.printElement.data.length; // 总共展示项
console.log(listColumn, '=---', totalNum);
const ifNeedColspan = totalNum % listColumn; // 展示项的数量取余一行展示的项的数量,如果没有余数则无须列合并,否则最后一项需要进行列合并
const cellStyle = 'border:1px solid #000;border-top:none;border-left:none;word-break:break-all';
const tableBodyDomArr = itemObj.printElement.data.map((item, index) => {
let trStr = '';
if (index % listColumn === 0) {
trStr += '<tr>';
let itemTh = `<th style="${cellStyle}">${item.label}</th><td style="${cellStyle}">${item.value}</td>`;
// 如果是最后一列并且有展示不完全的行,则最后一个td需要进行列合并
if ((index === totalNum - 1) && ifNeedColspan !== 0) {
const colspanNum = (listColumn - ifNeedColspan) * 2 + 1;
itemTh = `<th style="${cellStyle}">${item.label}</th><td colspan=${colspanNum} style="${cellStyle}">${item.value}</td>`;
trStr += itemTh;
if (index % listColumn === listColumn - 1) {
trStr += '</tr>';
return trStr;
console.log(tableBodyDomArr, 'tableBodyDomArr');
itemDom += `<table style='font-size:12px;border:1px solid #000;border-bottom:none;border-right:none;text-align:center;' cellspacing='0'>
${tableBodyDomArr.join('')}
</table>`;
default:
break;
// 如果有title需要将title和content布局
const flexItemDom = `<div style="display:flex;flex-direction:column;${itemObj.renderStyle || ''}">${itemDom}</div>`;
printDom.push(flexItemDom);
return printDom;
// 执行打印
const getPrintDom = (data) => {
const printDom = getPrintItemDom(data);
let printDomStr = printDom.join(''); // 最终打印的结构及样式
const iframe = document.createElement('IFRAME'); // 创建iframe
let doc = null; // 打印的文档
iframe.setAttribute('style', 'width:0;height:0;left:0;top:0'); // 设置iframe的样式
// iframe.setAttribute('style', 'width:800px;height:900px;left:0;top:0;z-index:2000;background:gold;'); // 设置iframe的样式--调试的时候换成这个
document.body.appendChild(iframe); // 将iframe追加进body
doc = iframe.contentWindow.document; // 获取iframe的文档
doc.open(); // 开始写入iframe
doc.write(printDomStr); // 写入打印的dom数据
doc.close(); // 结束写入,关闭文档
iframe.contentWindow.focus(); // 使iframe作为打印的容器
iframe.contentWindow.print(); // 调起打印
setTimeout(() => {
document.body.removeChild(iframe); // 删除iframe
},200);
// 调用打印
const doPrint = () => {
const printDatas = [
{ // dom字符串,可以试任意的dom字符串
type: 'domstr',
printElement: { data: `<h3>打印数据测试</h3>` },
renderStyle: 'text-align:center'
}, { // 表格
type: 'table',
title: 'table类型的数据',
printElement: {
columns: testTableColumns,
data: testTableData
renderStyle: 'width:100%;margin-bottom:20px;'
}, { // 描述列表,类似于antd的Descriptions展示样式(当然这里只是最基本的样式)
type: 'descriptions',
title: 'descriptions类型的数据',
printElement: {
columns: 3, // 一行展示几项数据
data: [
{label: '姓名', value: '张三'},
{label: '年龄', value: '32'},
{label: '电话', value: '8008208000'},
{label: '邮箱', value: '123@qq.com'},
{label: '户籍所在地', value: '北京'},
{label: '民族', value: '汉'},
{label: '职业', value: '老师'},
renderStyle: 'margin-bottom:20px;'
title: '有children的元素',
printElement: {
children: [{
type: 'domstr',
printElement: { data: `<h6>left</h6>` },
renderStyle: 'width: 30%;'
type: 'descriptions',
printElement: {
columns: 2,
data: [
{ label: 'color', value: 'red'},
{ label: 'color', value: 'yellow'},
{ label: 'color', value: 'black'},
{ label: 'color', value: 'pink'},
renderStyle: 'flex:1;'
renderStyle: 'display:flex;width:100%;align-items:center'
getPrintDom(printDatas); // 调用打印
// 给button绑定打印事件
const btnEl = document.getElementById('actionBtn');
btnEl.addEventListener('click', doPrint);
</script>
</html>
暂时就是这些,写的比较简陋,主要是用来展示打印表格。如果有更好的方法和插件或者意见,欢迎评论~