|
|
@@ -354,34 +354,56 @@ export default {
|
|
|
if (!cell.style.backgroundColor) {
|
|
|
cell.style.backgroundColor = '#f5f5f5';
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
+ // 获取单元格的原始对齐方式
|
|
|
+ const cellComputedStyle = window.getComputedStyle(cell);
|
|
|
+ const originalTextAlign = cellComputedStyle.getPropertyValue('text-align') ||
|
|
|
+ cell.style.textAlign ||
|
|
|
+ referenceStyle.getPropertyValue('text-align') || 'left';
|
|
|
+
|
|
|
// 处理单元格内的超链接
|
|
|
const cellLinks = cell.querySelectorAll('a');
|
|
|
cellLinks.forEach(cellLink => {
|
|
|
const span = document.createElement('span');
|
|
|
- span.textContent = cellLink.textContent;
|
|
|
|
|
|
- // 直接应用参考样式
|
|
|
+ // 获取链接的文本内容,并彻底清理中间的换行符
|
|
|
+ let linkText = cellLink.textContent;
|
|
|
+
|
|
|
+ // 彻底清理文本中间的换行符和多余空白,但保持单词间的单个空格
|
|
|
+ // 使用更严格的正则表达式来确保清理所有类型的空白字符
|
|
|
+ linkText = linkText.replace(/[\s\n\r\t\f\v]+/g, ' ').trim();
|
|
|
+
|
|
|
+ span.textContent = linkText;
|
|
|
+
|
|
|
+ // 应用参考样式
|
|
|
span.style.fontWeight = referenceStyle.getPropertyValue('font-weight') || 'bold';
|
|
|
span.style.fontSize = referenceStyle.getPropertyValue('font-size') || '14px';
|
|
|
span.style.fontFamily = referenceStyle.getPropertyValue('font-family') || 'Arial, sans-serif';
|
|
|
span.style.color = referenceStyle.getPropertyValue('color') || '#000000';
|
|
|
- span.style.textAlign = referenceStyle.getPropertyValue('text-align') || 'left';
|
|
|
|
|
|
+ // 保持原始的对齐方式
|
|
|
+ span.style.textAlign = originalTextAlign;
|
|
|
+
|
|
|
// 移除链接样式
|
|
|
span.style.textDecoration = 'none';
|
|
|
span.style.cursor = 'default';
|
|
|
-
|
|
|
+
|
|
|
console.log('替换a标签,应用样式:', {
|
|
|
fontWeight: span.style.fontWeight,
|
|
|
fontSize: span.style.fontSize,
|
|
|
fontFamily: span.style.fontFamily,
|
|
|
color: span.style.color,
|
|
|
- backgroundColor: span.style.backgroundColor
|
|
|
+ textAlign: span.style.textAlign,
|
|
|
+ originalTextAlign: originalTextAlign
|
|
|
});
|
|
|
-
|
|
|
+
|
|
|
cellLink.parentNode.replaceChild(span, cellLink);
|
|
|
});
|
|
|
+
|
|
|
+ // 确保单元格本身保持正确的对齐方式
|
|
|
+ if (!cell.style.textAlign && originalTextAlign !== 'left') {
|
|
|
+ cell.style.textAlign = originalTextAlign;
|
|
|
+ }
|
|
|
});
|
|
|
});
|
|
|
|
|
|
@@ -435,7 +457,15 @@ export default {
|
|
|
link.parentNode.replaceChild(span, link);
|
|
|
});
|
|
|
|
|
|
- const result = this.filterTrailingWhitespace(tempDiv.innerHTML);
|
|
|
+ // 过滤末尾的空格和换行
|
|
|
+ let result = this.filterTrailingWhitespace(tempDiv.innerHTML);
|
|
|
+
|
|
|
+ // 额外安全措施:对所有表头进行最终的换行符清理
|
|
|
+ result = this.finalHeaderCleanup(result);
|
|
|
+
|
|
|
+ // 专门清理包含br标签的span元素
|
|
|
+ result = this.cleanSpanWithBrTags(result);
|
|
|
+
|
|
|
console.log('处理完成后的HTML:', result);
|
|
|
return result;
|
|
|
} catch (error) {
|
|
|
@@ -443,55 +473,432 @@ export default {
|
|
|
return htmlContent; // 如果处理失败,返回原始内容
|
|
|
}
|
|
|
},
|
|
|
- // 过滤末尾空格和换行的方法 - 只处理文本末尾,不影响格式
|
|
|
- filterTrailingWhitespace(htmlContent) {
|
|
|
+
|
|
|
+ // 专门清理包含br标签的span元素
|
|
|
+ cleanSpanWithBrTags(htmlContent) {
|
|
|
try {
|
|
|
if (!htmlContent) return htmlContent;
|
|
|
+
|
|
|
+ // 使用正则表达式直接清理HTML字符串中的问题标签
|
|
|
+ let cleanedHtml = htmlContent;
|
|
|
|
|
|
+ // 清理各种形式的包含br的span标签
|
|
|
+ const patterns = [
|
|
|
+ // 匹配 <span style="font-family: Arial; font-size: 14;"><br></span> 等具体样式
|
|
|
+ /<span[^>]*style="[^"]*font-family:\s*Arial[^"]*"[^>]*>\s*<br\s*\/?>\s*<\/span>/gi,
|
|
|
+ // 匹配 <span style="font-family: Arial; font-size: 14;"><br /></span>
|
|
|
+ /<span[^>]*style="[^"]*font-family:\s*Arial[^"]*"[^>]*>\s*<br\s+\/>\s*<\/span>/gi,
|
|
|
+ // 匹配任何只包含br的span标签(通用模式)
|
|
|
+ /<span[^>]*>\s*<br\s*\/?>\s*<\/span>/gi,
|
|
|
+ // 匹配任何只包含br/的span标签
|
|
|
+ /<span[^>]*>\s*<br\s+\/>\s*<\/span>/gi,
|
|
|
+ // 匹配包含多个br的span标签
|
|
|
+ /<span[^>]*>\s*(<br\s*\/?>)+\s*<\/span>/gi,
|
|
|
+ // 匹配包含空白和br的span标签
|
|
|
+ /<span[^>]*>\s*[\s\n\r\t]*(<br\s*\/?>)+[\s\n\r\t]*<\/span>/gi
|
|
|
+ ];
|
|
|
+
|
|
|
+ patterns.forEach(pattern => {
|
|
|
+ const matches = cleanedHtml.match(pattern);
|
|
|
+ if (matches) {
|
|
|
+ console.log('发现需要清理的span br标签:', matches);
|
|
|
+ cleanedHtml = cleanedHtml.replace(pattern, '');
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ if (cleanedHtml !== htmlContent) {
|
|
|
+ console.log('清理span br标签完成');
|
|
|
+ }
|
|
|
+
|
|
|
+ return cleanedHtml;
|
|
|
+ } catch (error) {
|
|
|
+ console.error('清理span br标签时出错:', error);
|
|
|
+ return htmlContent;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 最终的表头清理方法,确保所有表头文本都没有中间的换行符
|
|
|
+ finalHeaderCleanup(htmlContent) {
|
|
|
+ try {
|
|
|
+ if (!htmlContent) return htmlContent;
|
|
|
+
|
|
|
// 创建临时DOM元素来解析HTML
|
|
|
const tempDiv = document.createElement('div');
|
|
|
tempDiv.innerHTML = htmlContent;
|
|
|
-
|
|
|
- // 只处理文本节点末尾的空白,不处理br标签
|
|
|
- const processTextNodes = (node) => {
|
|
|
- if (node.nodeType === Node.TEXT_NODE) {
|
|
|
- // 只处理纯文本节点末尾的空格和换行,保留其他空白
|
|
|
- node.textContent = node.textContent.replace(/\s+$/, '');
|
|
|
- } else if (node.nodeType === Node.ELEMENT_NODE) {
|
|
|
- // 递归处理子节点
|
|
|
- for (let child of node.childNodes) {
|
|
|
- processTextNodes(child);
|
|
|
+
|
|
|
+ // 处理所有表格的表头
|
|
|
+ const tables = tempDiv.querySelectorAll('table');
|
|
|
+ tables.forEach(table => {
|
|
|
+ // 处理所有表头单元格
|
|
|
+ const headerCells = table.querySelectorAll('th, thead td, tr:first-child td');
|
|
|
+
|
|
|
+ headerCells.forEach(cell => {
|
|
|
+ // 获取所有文本节点
|
|
|
+ const textNodes = [];
|
|
|
+ const walker = document.createTreeWalker(
|
|
|
+ cell,
|
|
|
+ NodeFilter.SHOW_TEXT,
|
|
|
+ null,
|
|
|
+ false
|
|
|
+ );
|
|
|
+
|
|
|
+ let textNode;
|
|
|
+ while (textNode = walker.nextNode()) {
|
|
|
+ textNodes.push(textNode);
|
|
|
}
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- // 处理所有子节点的文本末尾空白
|
|
|
- for (let child of tempDiv.childNodes) {
|
|
|
- processTextNodes(child);
|
|
|
- }
|
|
|
+
|
|
|
+ // 清理所有文本节点
|
|
|
+ textNodes.forEach(node => {
|
|
|
+ const originalText = node.textContent;
|
|
|
+ // 使用最严格的正则表达式清理所有空白字符
|
|
|
+ const cleanedText = originalText.replace(/[\s\n\r\t\f\v]+/g, ' ').trim();
|
|
|
+
|
|
|
+ if (originalText !== cleanedText) {
|
|
|
+ node.textContent = cleanedText;
|
|
|
+ console.log('最终清理表头文本:', `"${originalText}" -> "${cleanedText}"`);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 清理可能存在的空元素和包含br的span
|
|
|
+ const emptyElements = cell.querySelectorAll('span, div, p');
|
|
|
+ emptyElements.forEach(element => {
|
|
|
+ const textContent = element.textContent.trim();
|
|
|
+ const hasOnlyBr = element.innerHTML.trim() === '<br>' ||
|
|
|
+ element.innerHTML.trim() === '<br/>' ||
|
|
|
+ element.innerHTML.trim() === '<br />';
|
|
|
+ const isEmpty = textContent === '';
|
|
|
+
|
|
|
+ if ((isEmpty || hasOnlyBr) && !element.querySelector('img')) {
|
|
|
+ element.remove();
|
|
|
+ console.log('最终清理:移除空的表头元素:', element, 'innerHTML:', element.innerHTML);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 特别处理:清理所有包含br标签的span元素
|
|
|
+ const spansWithBr = cell.querySelectorAll('span');
|
|
|
+ spansWithBr.forEach(span => {
|
|
|
+ const innerHTML = span.innerHTML.trim();
|
|
|
+ if (innerHTML === '<br>' || innerHTML === '<br/>' || innerHTML === '<br />') {
|
|
|
+ span.remove();
|
|
|
+ console.log('最终清理:移除只包含br的span元素:', span);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ return tempDiv.innerHTML;
|
|
|
+ } catch (error) {
|
|
|
+ console.error('最终表头清理时出错:', error);
|
|
|
+ return htmlContent;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 专门处理表头内容,防止在表头中间添加换行符(适用于所有对齐方式)
|
|
|
+ processHeaderContent(headerCell) {
|
|
|
+ try {
|
|
|
+ // 获取单元格的原始对齐方式
|
|
|
+ const cellComputedStyle = window.getComputedStyle(headerCell);
|
|
|
+ const textAlign = cellComputedStyle.getPropertyValue('text-align') || 'left';
|
|
|
|
|
|
- // 获取处理后的HTML
|
|
|
- let result = tempDiv.innerHTML;
|
|
|
+ console.log('处理表头单元格对齐方式:', textAlign, headerCell);
|
|
|
|
|
|
- // 只移除整个内容末尾的空白字符,不移除标签间的空白
|
|
|
- result = result.replace(/\s+$/, '');
|
|
|
+ // 获取所有文本节点
|
|
|
+ const textNodes = [];
|
|
|
+ const walker = document.createTreeWalker(
|
|
|
+ headerCell,
|
|
|
+ NodeFilter.SHOW_TEXT,
|
|
|
+ null,
|
|
|
+ false
|
|
|
+ );
|
|
|
|
|
|
- // 只移除整个内容开头的空白字符
|
|
|
- result = result.replace(/^\s+/, '');
|
|
|
+ let textNode;
|
|
|
+ while (textNode = walker.nextNode()) {
|
|
|
+ textNodes.push(textNode);
|
|
|
+ }
|
|
|
|
|
|
- // 使用正则表达式只移除整个内容末尾的br标签
|
|
|
- // 这个正则表达式确保只匹配整个字符串末尾的br标签
|
|
|
- result = result.replace(/(<br\s*\/?>)+$/gi, '');
|
|
|
+ // 清理所有文本节点中的换行符和多余空白
|
|
|
+ textNodes.forEach(node => {
|
|
|
+ const originalText = node.textContent;
|
|
|
+
|
|
|
+ // 清理文本中间的换行符和多余空白,但保持单词间的单个空格
|
|
|
+ // 这个正则表达式会:
|
|
|
+ // 1. 将多个连续的空白字符(包括换行符、制表符、空格)替换为单个空格
|
|
|
+ // 2. 清理开头和结尾的空白
|
|
|
+ const cleanedText = originalText.replace(/\s+/g, ' ').trim();
|
|
|
+
|
|
|
+ if (originalText !== cleanedText) {
|
|
|
+ node.textContent = cleanedText;
|
|
|
+ console.log('清理表头文本:', `"${originalText}" -> "${cleanedText}"`);
|
|
|
+ }
|
|
|
+ });
|
|
|
|
|
|
- // 移除末尾的span标签如果只包含br标签
|
|
|
- result = result.replace(/<span[^>]*>(<br\s*\/?>)+<\/span>$/gi, '');
|
|
|
+ // 确保单元格保持原始的对齐方式
|
|
|
+ if (!headerCell.style.textAlign && textAlign !== 'left') {
|
|
|
+ headerCell.style.textAlign = textAlign;
|
|
|
+ }
|
|
|
|
|
|
- // 移除末尾的div标签如果只包含br标签
|
|
|
- result = result.replace(/<div[^>]*>(<br\s*\/?>)+<\/div>$/gi, '');
|
|
|
+ // 额外处理:清理单元格内可能存在的空元素和包含br的span
|
|
|
+ const emptyElements = headerCell.querySelectorAll('span, div, p');
|
|
|
+ emptyElements.forEach(element => {
|
|
|
+ // 检查是否为空元素或只包含br标签的span
|
|
|
+ const textContent = element.textContent.trim();
|
|
|
+ const hasOnlyBr = element.innerHTML.trim() === '<br>' || element.innerHTML.trim() === '<br/>';
|
|
|
+ const isEmpty = textContent === '';
|
|
|
+
|
|
|
+ if ((isEmpty || hasOnlyBr) && !element.querySelector('img')) {
|
|
|
+ element.remove();
|
|
|
+ console.log('移除空的表头元素:', element, 'innerHTML:', element.innerHTML);
|
|
|
+ }
|
|
|
+ });
|
|
|
|
|
|
- // 移除末尾的p标签如果只包含br标签
|
|
|
- result = result.replace(/<p[^>]*>(<br\s*\/?>)+<\/p>$/gi, '');
|
|
|
+ // 特别处理:清理包含br标签的span元素
|
|
|
+ const spansWithBr = headerCell.querySelectorAll('span');
|
|
|
+ spansWithBr.forEach(span => {
|
|
|
+ // 检查span是否只包含br标签
|
|
|
+ const innerHTML = span.innerHTML.trim();
|
|
|
+ if (innerHTML === '<br>' || innerHTML === '<br/>' || innerHTML === '<br />') {
|
|
|
+ span.remove();
|
|
|
+ console.log('移除只包含br的span元素:', span);
|
|
|
+ }
|
|
|
+ });
|
|
|
|
|
|
+ return headerCell;
|
|
|
+ } catch (error) {
|
|
|
+ console.error('处理表头内容时出错:', error);
|
|
|
+ return headerCell;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 过滤末尾空格和换行的方法 - 只处理文本末尾,不影响格式
|
|
|
+ filterTrailingWhitespace(htmlContent) {
|
|
|
+ try {
|
|
|
+ if (!htmlContent) return htmlContent;
|
|
|
+
|
|
|
+ // 创建临时DOM元素来解析HTML
|
|
|
+ const tempDiv = document.createElement('div');
|
|
|
+ tempDiv.innerHTML = htmlContent;
|
|
|
+
|
|
|
+ // 专门处理表格单元格内容的函数 - 只处理非表头单元格
|
|
|
+ const processTableCellContent = (cell) => {
|
|
|
+ console.log('处理非表头单元格:', cell, '内容:', cell.innerHTML);
|
|
|
+
|
|
|
+ // 递归处理所有文本节点的末尾空白
|
|
|
+ const processTextNodes = (node) => {
|
|
|
+ if (node.nodeType === Node.TEXT_NODE) {
|
|
|
+ // 清理文本节点末尾的空白字符(包括换行符和空格)
|
|
|
+ const original = node.textContent;
|
|
|
+ node.textContent = node.textContent.replace(/[\s\n\r\t]+$/, '');
|
|
|
+ if (original !== node.textContent) {
|
|
|
+ console.log('清理文本节点:', `"${original}" -> "${node.textContent}"`);
|
|
|
+ }
|
|
|
+ } else if (node.nodeType === Node.ELEMENT_NODE) {
|
|
|
+ // 递归处理所有子节点
|
|
|
+ Array.from(node.childNodes).forEach(processTextNodes);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 处理单元格内的所有文本节点
|
|
|
+ Array.from(cell.childNodes).forEach(processTextNodes);
|
|
|
+
|
|
|
+ // 特别处理:清理单元格内嵌套元素末尾的br标签和空白
|
|
|
+ const nestedElements = cell.querySelectorAll('span, div, p, strong, em, b, i, a');
|
|
|
+ nestedElements.forEach(element => {
|
|
|
+ // 递归处理嵌套元素的文本节点
|
|
|
+ Array.from(element.childNodes).forEach(processTextNodes);
|
|
|
+
|
|
|
+ // 清理元素末尾的br标签
|
|
|
+ let innerHTML = element.innerHTML;
|
|
|
+ const originalInnerHTML = innerHTML;
|
|
|
+
|
|
|
+ // 移除末尾的br标签
|
|
|
+ innerHTML = innerHTML.replace(/(<br\s*\/?>)+$/gi, '');
|
|
|
+ // 移除末尾的空白字符
|
|
|
+ innerHTML = innerHTML.replace(/[\s\n\r\t]+$/, '');
|
|
|
+
|
|
|
+ if (innerHTML !== originalInnerHTML) {
|
|
|
+ element.innerHTML = innerHTML;
|
|
|
+ console.log('清理嵌套元素:', element.tagName, `"${originalInnerHTML}" -> "${innerHTML}"`);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 最终清理:直接处理单元格的innerHTML来移除末尾的br和空白
|
|
|
+ let cellHTML = cell.innerHTML;
|
|
|
+ const originalCellHTML = cellHTML;
|
|
|
+
|
|
|
+ // 多次处理确保彻底清理
|
|
|
+ let previousHTML;
|
|
|
+ do {
|
|
|
+ previousHTML = cellHTML;
|
|
|
+ // 移除末尾的br标签
|
|
|
+ cellHTML = cellHTML.replace(/(<br\s*\/?>)+$/gi, '');
|
|
|
+ // 移除末尾的空白字符(包括换行、空格等)
|
|
|
+ cellHTML = cellHTML.replace(/[\s\n\r\t]+$/, '');
|
|
|
+ // 移除末尾的空span、div等标签
|
|
|
+ cellHTML = cellHTML.replace(/<(span|div|p)[^>]*>\s*<\/\1>$/gi, '');
|
|
|
+ } while (cellHTML !== previousHTML);
|
|
|
+
|
|
|
+ if (cellHTML !== originalCellHTML) {
|
|
|
+ cell.innerHTML = cellHTML;
|
|
|
+ console.log('最终清理非表头单元格:', `"${originalCellHTML}" -> "${cellHTML}"`);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清理单元格内可能存在的空文本节点
|
|
|
+ const walker = document.createTreeWalker(
|
|
|
+ cell,
|
|
|
+ NodeFilter.SHOW_TEXT,
|
|
|
+ null,
|
|
|
+ false
|
|
|
+ );
|
|
|
+
|
|
|
+ let textNode;
|
|
|
+ const nodesToRemove = [];
|
|
|
+ while (textNode = walker.nextNode()) {
|
|
|
+ if (textNode.textContent.trim() === '') {
|
|
|
+ nodesToRemove.push(textNode);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ nodesToRemove.forEach(node => node.remove());
|
|
|
+ };
|
|
|
+
|
|
|
+ // 处理所有表格,但只处理非表头内容
|
|
|
+ const allTables = tempDiv.querySelectorAll('table');
|
|
|
+ allTables.forEach(table => {
|
|
|
+ console.log('处理表格,但保护表头:', table);
|
|
|
+
|
|
|
+ // 1. 明确保护表头内容:不处理thead中的任何单元格,但需要处理居中对齐的换行符问题
|
|
|
+ const theadCells = table.querySelectorAll('thead th, thead td');
|
|
|
+ console.log('保护表头单元格数量:', theadCells.length);
|
|
|
+ theadCells.forEach(cell => {
|
|
|
+ console.log('跳过表头单元格:', cell, '内容:', cell.innerHTML);
|
|
|
+ // 使用专门的方法处理表头内容,防止居中表头中间出现换行符
|
|
|
+ this.processHeaderContent(cell);
|
|
|
+ });
|
|
|
+
|
|
|
+ // 2. 明确保护表格标题行(通常是第一行包含th的行)
|
|
|
+ const allRows = table.querySelectorAll('tr');
|
|
|
+ const headerRows = [];
|
|
|
+
|
|
|
+ // 识别可能的表头行(包含th的行或第一行)
|
|
|
+ allRows.forEach((row, index) => {
|
|
|
+ const hasTh = row.querySelector('th');
|
|
|
+ const isFirstRow = index === 0;
|
|
|
+ if (hasTh || isFirstRow) {
|
|
|
+ headerRows.push(row);
|
|
|
+ console.log('识别为表头行:', row);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 保护表头行中的所有单元格,但需要处理居中对齐的换行符问题
|
|
|
+ headerRows.forEach(row => {
|
|
|
+ const headerCells = row.querySelectorAll('th, td');
|
|
|
+ headerCells.forEach(cell => {
|
|
|
+ console.log('保护表头行中的单元格:', cell, '内容:', cell.innerHTML);
|
|
|
+ // 使用专门的方法处理表头内容,防止居中表头中间出现换行符
|
|
|
+ this.processHeaderContent(cell);
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ // 3. 只处理tbody中的非表头td单元格
|
|
|
+ const tbodyTds = table.querySelectorAll('tbody td');
|
|
|
+ tbodyTds.forEach(td => {
|
|
|
+ // 双重检查:确保这个td不在任何表头行中
|
|
|
+ const parentRow = td.closest('tr');
|
|
|
+ const isInHeaderRow = headerRows.includes(parentRow);
|
|
|
+
|
|
|
+ if (!isInHeaderRow) {
|
|
|
+ processTableCellContent(td);
|
|
|
+ } else {
|
|
|
+ console.log('跳过表头行中的td:', td);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 4. 处理没有tbody的表格:只处理非表头行的td
|
|
|
+ const hasTbody = table.querySelector('tbody');
|
|
|
+ if (!hasTbody) {
|
|
|
+ console.log('表格没有tbody,处理非表头行');
|
|
|
+
|
|
|
+ allRows.forEach((row, index) => {
|
|
|
+ const isHeaderRow = headerRows.includes(row);
|
|
|
+
|
|
|
+ if (!isHeaderRow) {
|
|
|
+ console.log('处理非表头行:', row);
|
|
|
+ const cells = row.querySelectorAll('td');
|
|
|
+ cells.forEach(cell => {
|
|
|
+ processTableCellContent(cell);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ console.log('跳过表头行:', row);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 额外安全措施:明确不处理任何th元素,但需要处理居中对齐的换行符问题
|
|
|
+ const allThs = table.querySelectorAll('th');
|
|
|
+ allThs.forEach(th => {
|
|
|
+ console.log('保护所有th元素:', th, '内容:', th.innerHTML);
|
|
|
+ // 使用专门的方法处理表头内容,防止居中表头中间出现换行符
|
|
|
+ this.processHeaderContent(th);
|
|
|
+ });
|
|
|
+
|
|
|
+ // 6. 额外检查:确保没有遗漏需要保护的单元格
|
|
|
+ const allCells = table.querySelectorAll('td, th');
|
|
|
+ allCells.forEach(cell => {
|
|
|
+ const parentRow = cell.closest('tr');
|
|
|
+ const isTh = cell.tagName.toLowerCase() === 'th';
|
|
|
+ const isInHeaderRow = headerRows.includes(parentRow);
|
|
|
+ const isInThead = cell.closest('thead');
|
|
|
+
|
|
|
+ if (isTh || isInHeaderRow || isInThead) {
|
|
|
+ console.log('确认保护单元格:', cell.tagName, '在表头中:', cell);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ // 处理非表格内容的文本节点(保持原有逻辑)
|
|
|
+ const processGeneralTextNodes = (node) => {
|
|
|
+ if (node.nodeType === Node.TEXT_NODE) {
|
|
|
+ const original = node.textContent;
|
|
|
+ node.textContent = node.textContent.replace(/\s+$/, '');
|
|
|
+ if (original !== node.textContent) {
|
|
|
+ console.log('清理一般文本节点:', `"${original}" -> "${node.textContent}"`);
|
|
|
+ }
|
|
|
+ } else if (node.nodeType === Node.ELEMENT_NODE && !node.closest('table')) {
|
|
|
+ // 递归处理非表格元素的子节点
|
|
|
+ Array.from(node.childNodes).forEach(processGeneralTextNodes);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 处理所有子节点的文本末尾空白(跳过表格内容)
|
|
|
+ Array.from(tempDiv.childNodes).forEach(processGeneralTextNodes);
|
|
|
+
|
|
|
+ // 获取处理后的HTML并进行最终清理
|
|
|
+ let result = tempDiv.innerHTML;
|
|
|
+
|
|
|
+ console.log('初步处理结果:', result);
|
|
|
+
|
|
|
+ // 最终清理步骤(不影响表头,因为表头已经在DOM中保护)
|
|
|
+ let previousResult;
|
|
|
+ do {
|
|
|
+ previousResult = result;
|
|
|
+
|
|
|
+ // 清理整个内容末尾的空白字符
|
|
|
+ result = result.replace(/[\s\n\r\t]+$/, '');
|
|
|
+
|
|
|
+ // 清理整个内容末尾的br标签
|
|
|
+ result = result.replace(/(<br\s*\/?>)+$/gi, '');
|
|
|
+
|
|
|
+ // 清理末尾的空标签
|
|
|
+ result = result.replace(/<(span|div|p)[^>]*>\s*<\/\1>$/gi, '');
|
|
|
+ result = result.replace(/<(\w+)[^>]*>(<br\s*\/?>)+<\/\1>$/gi, '');
|
|
|
+
|
|
|
+ } while (result !== previousResult);
|
|
|
+
|
|
|
+ // 清理开头的空白
|
|
|
+ result = result.replace(/^[\s\n\r\t]+/, '');
|
|
|
+
|
|
|
+ console.log('最终结果:', result);
|
|
|
+
|
|
|
return result;
|
|
|
} catch (error) {
|
|
|
console.error('过滤末尾空白时出错:', error);
|