jQuery hover行号整行高亮时如何获取同级文本节点设置样式
问题背景
当前HTML结构由XSLT生成,无法直接修改初始DOM,结构如下:
<div class="testoorig"> <h3>Testo originale</h3> <div id="pag_10"></div> <br><span class="lineNumb"><b>1</b></span> <orig>d</orig> sometext sometext <span class="term" id="#formes">formes</span> sometext sometext <span class="term" id="#memoire">mémoire</span>; <mentioned><u>punirai</u></mentioned>, <mentioned><u>punir</u></mentioned> <!-- Next line (totally 31) --> <br><span class="lineNumb"><b>2</b></span> ..... </div> <!-- #testoorig -->
现有jQuery代码实现hover行号高亮逻辑:
jQuery.fn.getParent = function (num) { var last = this[0]; for (var i = 0; i < num; i++) { last = last.parentNode; } return jQuery(last); }; $(document).on("mouseover", ".lineNumb", function(g){ target = $(this); target.css("background", "antiquewhite"); arr = target.getParent(0).nextUntil(".lineNumb"); for(i=0;i<arr.length;i++) { $(arr[i]).css("background", "antiquewhite"); } });
现存问题
jQuery的nextUntil()方法仅能获取同级的元素节点,会自动忽略未被标签包裹的裸文本节点,导致只有标签包裹的内容能应用高亮样式,裸文本(如示例中的sometext sometext)无法被选中高亮,需要实现整行全内容(含裸文本)的hover高亮效果,允许通过JS动态包裹元素的方案实现。
解决方案
核心原因
jQuery默认的节点遍历方法只会筛选nodeType=1的元素节点,文本节点(nodeType=3)、注释节点会被直接跳过,因此无法直接通过jQuery方法拿到裸文本。
最优方案是页面初始化时做一次DOM预处理,遍历原生DOM节点拿到每行包含的所有内容(含文本节点),统一包裹在行内容容器中,后续hover逻辑直接操作容器即可,性能更高逻辑更简单。
完整实现代码如下:
$(function() { // 预处理:遍历所有行号,将每行所有内容包裹进容器 $('.lineNumb').each(function() { const currentLineNode = this; const lineContentNodes = []; let pointer = currentLineNode.nextSibling; // 从行号后第一个节点开始遍历,直到遇到下一个行号/换行br为止 while (pointer) { if (pointer.nodeType === 1) { const $pointer = $(pointer); if ($pointer.hasClass('lineNumb') || pointer.tagName === 'BR') break; } lineContentNodes.push(pointer); pointer = pointer.nextSibling; } // 把收集到的所有节点(含文本、元素)包裹在统一容器内 if (lineContentNodes.length) { $(lineContentNodes).wrapAll('<span class="line-content"></span>'); } }); // 绑定hover事件,补充鼠标移出清除样式的逻辑 $(document) .on('mouseenter', '.lineNumb', function() { $(this).add($(this).next('.line-content')).css('background', 'antiquewhite'); }) .on('mouseleave', '.lineNumb', function() { $(this).add($(this).next('.line-content')).css('background', ''); }); });
代码说明
- 用原生DOM属性
nextSibling做遍历,不会跳过文本节点,能完整收集当前行的所有内容 - DOM预处理仅在页面加载时执行一次,后续hover不需要重复遍历节点,性能更好
- 补充了
mouseleave事件逻辑,解决鼠标移开后高亮残留的问题 - 完全不需要修改原有XSLT生成的初始DOM结构,适配现有场景
- 原有自定义的
getParent方法如果没有其他业务用途可以直接删除,新逻辑不需要依赖该方法
内容的提问来源于stack exchange,提问作者JustAnotherSimpleProgrammer__
相关产品推荐
相关产品推荐

