b/s 导出内容word中换行

本文介绍了一种将网页内容导出到Word文档时实现自动换行的方法。通过在代码中添加特定的HTML标签,可以使内容在Word中正确换行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

将网页中的内容导出到WORD中时。代码应添加<p><br></P>然后添加内容。就可以实现在WORD中换行。

如:

td1.InnerHtml="<p><br></P>&nbsp;&nbsp;&nbsp;&nbsp;word中自动换行";

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>工资条生成工具</title> <!-- 引入SheetJS库用于处理Excel文件 --> <script src="https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js"></script> <!-- 关键修复:使用支持样式的xlsx-style库替换基础版xlsx库 --> <script src="https://unpkg.com/xlsx-style@0.15.6/dist/xlsx.full.min.js"></script> <style> * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: "Microsoft YaHei", "SimHei", Arial, sans-serif; width: 100%; min-height: 100vh; padding: 20px; font-size: 14px; color: #333; line-height: 1.5; } h1 { text-align: center; margin-bottom: 25px; font-size: 24px; color: #2c3e50; } h2 { font-size: 18px; margin: 15px 0; color: #3498db; } .file-upload { border: 2px dashed #95a5a6; padding: 30px 20px; text-align: center; margin-bottom: 30px; cursor: pointer; border-radius: 6px; transition: all 0.3s ease; background-color: #f8f9fa; } .file-upload:hover, .file-upload.active { border-color: #3498db; background-color: #f1f7fc; } .file-upload p { font-size: 16px; color: #7f8c8d; } #fileInput { display: none; } .controls { display: flex; justify-content: center; margin: 20px 0; } .btn { background-color: #3498db; color: white; border: none; padding: 10px 20px; border-radius: 4px; cursor: pointer; font-size: 14px; transition: background-color 0.3s ease; display: flex; align-items: center; gap: 8px; } .btn:hover { background-color: #2980b9; } .btn:disabled { background-color: #bdc3c7; cursor: not-allowed; } #dataContainer { width: 100%; overflow-x: auto; margin: 0 auto; } table { width: 100%; min-width: 900px; border-collapse: collapse; table-layout: fixed; } th, td { border: 1px solid #ddd; padding: 12px 10px; text-align: left; word-wrap: break-word; word-break: break-all; height: 45px; } /* 数值列右对齐,方便查看 */ td.numeric { text-align: right; } /* 工资条表头样式 */ .salary-slip-header th { background-color: #ecf0f1; color: #2c3e50; font-weight: bold; position: sticky; top: 0; z-index: 2; } /* 合计行样式 */ .total-row td { background-color: #f8f9fa; font-weight: bold; } /* 签字行样式 */ .signature-row td { background-color: #f9f9f9; } tr:hover { background-color: #f1f7fc; } .message { color: #7f8c8d; text-align: center; padding: 50px 0; font-size: 16px; } .error { color: #e74c3c; } /* 无效数值样式 */ .invalid-value { background-color: #fff3cd; color: #856404; } .date-info { color: #2c3e50; font-size: 15px; margin: 15px 0; padding: 15px 12px; background-color: #f1f9f7; border-left: 3px solid #27ae60; border-radius: 4px; line-height: 1.8; min-height: 45px; } /* 响应式调整 */ @media (max-width: 1200px) { body { padding: 15px; font-size: 13px; } th, td { padding: 10px 8px; height: 40px; } .date-info { padding: 12px 10px; min-height: 40px; } } @media (max-width: 768px) { body { padding: 10px; font-size: 12px; } h1 { font-size: 20px; margin-bottom: 15px; } h2 { font-size: 16px; } .file-upload { padding: 20px 10px; margin-bottom: 20px; } th, td { padding: 8px 6px; height: 36px; } .date-info { padding: 10px 8px; min-height: 36px; } } </style> </head> <body> <h1>工资条生成工具</h1> <!-- 文件上传区域 --> <div class="file-upload" id="dropArea"> <p>点击或拖放工资表Excel文件到这里(支持多次上传更新)</p> <input type="file" id="fileInput" accept=".xlsx, .xls"> </div> <!-- 提取的信息 --> <div id="infoContainer" style="display: none;"> <div class="date-info"> <p><strong>公司名称:</strong><span id="companyName"></span></p> <p><strong>工资月份:</strong><span id="salaryMonth"></span></p> <p><strong>上次更新:</strong><span id="lastUpdated"></span></p> </div> </div> <!-- 控制按钮区域 --> <div class="controls"> <button id="exportBtn" class="btn" disabled> 导出工资条 </button> </div> <!-- 数据展示区域 --> <div id="dataContainer" style="display: none;"> <h2>工资条数据</h2> <table id="dataTable"> <tbody id="dataTableBody"> <!-- 提取的数据将在这里显示,每条数据带独立表头 --> </tbody> </table> </div> <!-- 消息区域 --> <div id="message" class="message">请上传符合格式要求的工资表Excel文件(.xlsx, .xls)</div> <script> // 获取DOM元素 const dropArea = document.getElementById('dropArea'); const fileInput = document.getElementById('fileInput'); const dataContainer = document.getElementById('dataContainer'); const dataTable = document.getElementById('dataTable'); const dataTableBody = document.getElementById('dataTableBody'); const message = document.getElementById('message'); const infoContainer = document.getElementById('infoContainer'); const companyName = document.getElementById('companyName'); const salaryMonth = document.getElementById('salaryMonth'); const lastUpdated = document.getElementById('lastUpdated'); const exportBtn = document.getElementById('exportBtn'); // 存储处理后的数据用于导出 let processedDataForExport = null; let currentDate = ''; // 定义预期的表头结构 const expectedHeaders = [ '序号', '部门', '姓名', '出勤', '基本工资', '岗位工资', '绩效', '浮动津贴', '扣除', '应发工资', '基本养老(个人)', '失业(个人)', '基本医疗(个人)', '大病(个人)', '公积金(个人)', '个税', '实发工资', '签字' ]; // 定义哪些列是数值类型(索引) const numericColumns = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; // 点击上传区域触发文件选择 dropArea.addEventListener('click', () => fileInput.click()); // 文件选择变化时处理 fileInput.addEventListener('change', (e) => { if (e.target.files.length > 0) { handleFile(e.target.files[0]); // 重置input值,允许重复选择同一文件 fileInput.value = ''; } }); // 拖放功能增强 dropArea.addEventListener('dragover', (e) => { e.preventDefault(); dropArea.classList.add('active'); }); dropArea.addEventListener('dragleave', () => { dropArea.classList.remove('active'); }); dropArea.addEventListener('drop', (e) => { e.preventDefault(); dropArea.classList.remove('active'); if (e.dataTransfer.files.length > 0) { handleFile(e.dataTransfer.files[0]); } }); // 导出按钮点击事件 exportBtn.addEventListener('click', exportToExcel); // 处理Excel文件 - 支持多次上传更新 function handleFile(file) { // 检查文件类型 if (!file.name.match(/\.(xlsx|xls)$/)) { showMessage('请上传Excel文件(.xlsx, .xls)', true); return; } showMessage(`正在解析文件: ${file.name}...`); const reader = new FileReader(); reader.onload = function(e) { try { // 读取并解析Excel文件 const data = new Uint8Array(e.target.result); const workbook = XLSX.read(data, { type: 'array' }); // 获取第一个工作表 const firstSheetName = workbook.SheetNames[1]; const worksheet = workbook.Sheets[firstSheetName]; // 转换为JSON const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 }); if (jsonData.length < 2) { showMessage('文件内容不符合要求,至少需要包含标题行和表头行', true); return; } // 处理数据并更新表格 processData(jsonData); // 更新最后上传时间 updateLastModifiedTime(); } catch (error) { showMessage('解析文件失败: ' + error.message, true); console.error(error); } }; reader.readAsArrayBuffer(file); } // 更新最后修改时间 function updateLastModifiedTime() { const now = new Date(); const formattedTime = now.toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' }); lastUpdated.textContent = formattedTime; infoContainer.style.display = 'block'; } // 处理数据,提取公司名称和日期并规范化表头 function processData(rawData) { // 提取标题行信息(第一行数据) let title = rawData[0][0] || ''; // 提取公司名称 const companyMatch = title.match(/^(.*?)\s*\d{4}/); const company = companyMatch ? companyMatch[1] : '未知公司'; // 提取日期 const datePattern = /(\d{4})\D*(\d{1,2})\D*月/; const dateMatch = title.match(datePattern); currentDate = dateMatch ? dateMatch[0] : ''; // 更新公司名称和工资月份信息 companyName.textContent = company; salaryMonth.textContent = currentDate; // 提取特定行列数据 const extractedData = extractSpecificData(rawData); // 处理数值数据 const processedData = processNumericData(extractedData); // 保存处理后的数据用于导出 processedDataForExport = processedData; // 启用导出按钮 exportBtn.disabled = false; // 显示处理后的数据(每条数据带独立表头) displayData(processedData, currentDate); } // 提取特定行列数据 function extractSpecificData(rawData) { // 转换Excel列字母为索引(A=0, B=1, C=2...) const columnMap = { 'A': 0, 'B': 1, 'C': 2, 'O': 14, 'Q': 16, 'R': 17, 'S': 18, 'T': 19, 'W': 22, 'X': 23, 'Y': 24, 'Z': 25, 'AA': 26, 'AB': 27, 'AC': 28, 'AE': 30, 'AG': 32, 'AH': 33 }; // 需要提取的列索引 const columnsToExtract = Object.values(columnMap); // 找到最后一行有数据的行索引 let lastDataRow = -1; for (let i = rawData.length - 1; i >= 0; i--) { const row = rawData[i]; if (row && row.some(cell => cell !== undefined && cell !== null && cell !== '')) { lastDataRow = i; break; } } // 计算行范围 const startRow = 5; // 第6行(0-based索引) const endRow = lastDataRow !== -1 ? lastDataRow - 6 : -1; // 验证行范围有效性 if (lastDataRow === -1) { console.warn('未找到有数据的行'); return []; } if (startRow >= endRow || endRow < 0) { console.warn(`数据行范围无效,开始行(${startRow+1}) >= 结束行(${endRow+1})`); showMessage(`数据行范围无效,开始行(${startRow+1}) >= 结束行(${endRow+1})`, true); return []; } // 提取数据到二维数组 const result = []; for (let i = startRow; i < endRow; i++) { const rowData = rawData[i] || []; const extractedRow = []; columnsToExtract.forEach(colIndex => { extractedRow.push(rowData[colIndex] !== undefined ? rowData[colIndex] : ''); }); result.push(extractedRow); } return result; } // 处理数值数据:校验并保留2位小数(四舍五入),空值不标红 function processNumericData(data) { return data.map(row => { return row.map((cell, index) => { // 检查当前列是否为数值列 if (numericColumns.includes(index)) { // 处理空值情况 if (cell === '' || cell === null || cell === undefined) { return { value: '', valid: true, // 空值视为有效 rawValue: 0 // 用于计算合计的原始数值 }; } // 尝试转换为数值 const num = parseFloat(cell); // 校验数值有效性 if (isNaN(num)) { return { value: cell, valid: false, rawValue: 0 }; } else { const roundedValue = Math.round(num * 100) / 100; return { value: roundedValue, valid: true, rawValue: roundedValue // 存储用于计算合计的数值 }; } } // 非数值列,直接返回原始值 return { value: cell, valid: true, rawValue: 0 }; }); }); } // 计算各列的总和 function calculateTotals(processedData) { const totals = new Array(expectedHeaders.length).fill(0); processedData.forEach(row => { row.forEach((cell, index) => { // 只对数值列进行求和 if (numericColumns.includes(index)) { totals[index] += cell.rawValue; } }); }); // 保留两位小数 return totals.map(total => Math.round(total * 100) / 100); } // 显示解析后的数据 - 每条数据前都添加表头,无间隔,最后添加合计行和签字行 function displayData(processedData, date) { // 清空表格 dataTableBody.innerHTML = ''; // 如果没有提取到数据,显示提示 if (processedData.length === 0) { const emptyRow = document.createElement('tr'); const emptyCell = document.createElement('td'); emptyCell.colSpan = expectedHeaders.length; emptyCell.textContent = '没有提取到符合条件的数据'; emptyRow.appendChild(emptyCell); dataTableBody.appendChild(emptyRow); } else { // 为每条数据添加表头(无间隔) processedData.forEach((row) => { // 添加表头行(每条数据前都添加) const headerRow = document.createElement('tr'); headerRow.className = 'salary-slip-header'; expectedHeaders.forEach((header) => { if (header === '应发工资' || header === '实发工资') { header += `(${date})`; } const th = document.createElement('th'); th.textContent = header; headerRow.appendChild(th); }); dataTableBody.appendChild(headerRow); // 添加数据行 const dataRow = document.createElement('tr'); row.forEach((cell, cellIndex) => { const td = document.createElement('td'); td.textContent = cell.value; // 数值列右对齐 if (numericColumns.includes(cellIndex)) { td.classList.add('numeric'); } // 标记无效数值 if (!cell.valid) { td.classList.add('invalid-value'); } dataRow.appendChild(td); }); dataTableBody.appendChild(dataRow); }); // 计算各列总和 const totals = calculateTotals(processedData); // 添加合计行(倒数第二行) const totalRow = document.createElement('tr'); totalRow.className = 'total-row'; // 前3个单元格合并,内容为"合计" const mergedCell = document.createElement('td'); mergedCell.colSpan = 3; mergedCell.textContent = '合计'; mergedCell.style.textAlign = 'center'; totalRow.appendChild(mergedCell); // 第4个单元格为空 const emptyCell = document.createElement('td'); totalRow.appendChild(emptyCell); // 5-17单元格为各列总和(索引4到16) for (let i = 4; i < expectedHeaders.length; i++) { const td = document.createElement('td'); td.textContent = totals[i]; if (i == expectedHeaders.length - 1) { td.textContent = ''; } if (numericColumns.includes(i)) { td.classList.add('numeric'); } totalRow.appendChild(td); } dataTableBody.appendChild(totalRow); // 添加签字行(最后一行) const signatureRow = document.createElement('tr'); signatureRow.className = 'signature-row'; // 制表 const makerCell = document.createElement('td'); makerCell.colSpan = 4; makerCell.textContent = '制表:'; signatureRow.appendChild(makerCell); // 财务 const financeCell = document.createElement('td'); financeCell.colSpan = 4; financeCell.textContent = '财务:'; signatureRow.appendChild(financeCell); // 审核 const auditCell = document.createElement('td'); auditCell.colSpan = 5; auditCell.textContent = '审核:'; signatureRow.appendChild(auditCell); // 审批 const approveCell = document.createElement('td'); approveCell.colSpan = 5; approveCell.textContent = '审批:'; signatureRow.appendChild(approveCell); dataTableBody.appendChild(signatureRow); } // 显示数据区域,隐藏消息 dataContainer.style.display = 'block'; message.style.display = 'none'; } // 导出数据到Excel function exportToExcel() { if (!processedDataForExport || processedDataForExport.length === 0) { showMessage('没有可导出的数据', true); return; } // 准备导出数据 const exportData = []; // 添加每条记录的表头和数据 processedDataForExport.forEach(row => { // 添加表头行 const headerRow = expectedHeaders.map(header => { if (header === '应发工资' || header === '实发工资') { return `${header}(${currentDate})`; } return header; }); exportData.push(headerRow); // 添加数据行 const dataRow = row.map(cell => cell.value); exportData.push(dataRow); }); // 计算合计 const totals = calculateTotals(processedDataForExport); // 准备合计行 const totalRow = []; // 前3个单元格合并为"合计" totalRow.push("合计"); totalRow.push(null); // 第二个单元格(合并后不需要) totalRow.push(null); // 第三个单元格(合并后不需要) totalRow.push(""); // 第四个单元格为空 // 添加5-17列的合计值 for (let i = 4; i < expectedHeaders.length - 1; i++) { totalRow.push(totals[i]); } exportData.push(totalRow); // 准备签字行 - 只在第一个单元格设置值,其他为空 const signatureRow = new Array(expectedHeaders.length).fill(null); signatureRow[0] = "制表: 财务: 审核: 审批:"; exportData.push(signatureRow); // 创建工作簿和工作表 const ws = XLSX.utils.aoa_to_sheet(exportData); // 设置单元格合并 if (exportData.length > 0) { const totalRowIndex = exportData.length - 2; // 合计行索引 const signatureRowIndex = exportData.length - 1; // 签字行索引 ws['!merges'] = [ // 合计行前3列合并 { s: { r: totalRowIndex, c: 0 }, e: { r: totalRowIndex, c: 2 } }, // 签字行A-R列合并为一个单元格 { s: { r: signatureRowIndex, c: 0 }, e: { r: signatureRowIndex, c: 17 } // 合并到第18列(R列) } ]; } // 设置固定行高 const range = XLSX.utils.decode_range(ws['!ref']); ws['!rows'] = []; // 初始化行配置数组 for (let R = 0; R <= range.e.r; R++) { // 为每一行设置固定高度20 ws['!rows'][R] = { hpt: 30 }; // hpt单位是1/20点,所以20像素需要乘以20 } // 使用自定义列宽,从第一列开始依次应用 const customWidths = [3.92, 4.8, 5, 4.05, 7.43, 7.68, 3.55, 4.93, 4.18, 12.05, 6.93, 6.93, 7.3, 6.93, 7.55, 5.68, 12.18, 9.43 ]; // 为每个表头应用对应的自定义宽度 ws['!cols'] = customWidths.map(width => ({ // 保留一位小数并转换为数字,确保宽度值正确 wch: parseFloat(width.toFixed(2)) })); // 定义包含自动换行的单元格样式 const cellStyle = { font: { sz: 10 // 小一号字体 }, alignment: { wrapText: true // 核心配置:启用自动换行 } }; // 应用样式到所有单元格 for (const cellAddress in ws) { // 跳过非单元格属性(如!cols、!rows等) if (cellAddress.startsWith('!')) continue; if (ws[cellAddress]) { // 合并已有样式与自动换行样式 ws[cellAddress].s = { ...ws[cellAddress].s, ...cellStyle }; } else { // 为空白单元格设置样式 ws[cellAddress] = { s: cellStyle }; } } // 创建工作簿并添加工作表 const wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "工资条"); // 生成文件名(包含公司名称和日期) const company = companyName.textContent || "未知公司"; const fileName = `${company}_${currentDate || new Date().toLocaleDateString()}_工资条.xlsx`; // 导出文件 XLSX.writeFile(wb, fileName); } // 显示消息 function showMessage(text, isError = false) { message.textContent = text; message.className = isError ? 'message error' : 'message'; message.style.display = 'block'; dataContainer.style.display = 'none'; infoContainer.style.display = 'none'; } </script> </body> </html> 希望导出后有内容部分加边框,字体为宋体10号字,自动换行,对其方式上下左右居中,奇数行加粗
最新发布
08-07
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值