Javascript 修改HTML,同时保留现有元素和事件侦听器

Javascript 修改HTML,同时保留现有元素和事件侦听器,javascript,jquery,html,google-chrome-extension,split,Javascript,Jquery,Html,Google Chrome Extension,Split,我是新来的。我试着向你解释我的问题。 我正在为管理DOM的Chrome开发一个扩展。 我必须将标记元素中的每个单词拆分,以便在每个单词上的一些css功能之后应用,但保留可能位于标记中的其他标记元素(,等) 网页中可能的文本示例: <p> Sed ut <a> perspiciatis unde omnis </a> iste natus <em> error sit </em> voluptatem <st

我是新来的。我试着向你解释我的问题。 我正在为管理DOM的Chrome开发一个扩展。 我必须将
标记元素中的每个单词拆分,以便在每个单词上的一些css功能之后应用,但保留可能位于
标记中的其他标记元素(
等)

网页中可能的文本示例:

<p> 
   Sed ut <a> perspiciatis unde omnis </a> 
   iste natus <em> error sit </em> 
   voluptatem <strong> accusantium </strong> 
   doloremque laudantium 
</p>


全方位透视
iste自然错误
voluptatemaccusantium
劳丹蒂姆酒店

使用jQuery,我想在每个单词周围放置一个
标记,以定义一个类属性,用于css。 我发现这个代码可以正确地分割单词(属于<代码> <代码>,但不考虑代码中的其他可能元素> <>>代码>

使用的代码(不满足我的需要):


$(“p”)。每个(函数(){
var originalText=$(this.text().split(“”);
var SpandText=[];
对于(变量i=0;i
在上面显示的示例中,此代码生成以下输出,删除其他标记元素:

<p> 
    <span>Sed</span> 
    <span>ut</span> 
    <span>perspiciatis</span> 
    <span>unde</span> 
    <span>omnis</span> 
    <span>iste</span> 
    <span>natus</span> 
    <span>error</span> 
    <span>sit</span> 
    <span>voluptatem</span> 
    <span>accusantium</span>
    <span>doloremque</span> 
    <span>laudantium</span> 
</p>


塞德
美国犹他州
透视术
unde
奥姆尼斯
伊斯特
纳图斯
错误
坐着
沃鲁帕特姆
accusantium
多洛雷姆格
劳丹提姆

这接近于我需要的解决方案,但在本例中,示例中的所有标记(
)都被删除并替换为
标记

相反,我希望保留
的html结构,并且只为每个单词插入
..

这就是我想要实现的输出:

<p> 
    <span>Sed</span> 
    <span>ut</span> 
    <a> <span>perspiciatis</span> <span>unde</span> <span>omnis</span> </a>
    <span>iste</span> 
    <span>natus</span> 
    <em> <span>error</span> <span>sit</span> </em>
    <span>voluptatem</span> 
    <strong> <span>accusantium</span> </strong>
    <span>doloremque</span> 
    <span>laudantium</span> 
</p>


塞德
美国犹他州
全向透视
伊斯特
纳图斯
错误定位
沃鲁帕特姆
accusantium
多洛雷姆格
劳丹提姆

你能帮我吗?

永远不要通过innerHTML或jQuery的HTML()替换HTML 替换HTML会破坏JavaScript中添加到子元素的所有事件侦听器,并使浏览器重新解析整个事件,这是一个CPU密集型操作,因此在速度较慢的设备上可能会变慢。不要这样做

仅递归处理文本节点:
const span=document.createElement('span');
span.className='foo';
appendChild(document.createTextNode(“”));
//根据HTML规范,它们将显示为文本
常量skipTags=['textarea','rp'];
for(document.getElementsByTagName('p')的常数p){
const walker=document.createTreeWalker(p,NodeFilter.SHOW_TEXT);
//首先收集节点,因为我们无法在漫游时插入新的跨度节点
常量textNodes=[];
for(设n;(n=walker.nextNode());){
if(n.nodeValue.trim()&&!skipTags.includes(n.parentNode.localName)){
textNodes.push(n);
}
}
for(文本节点的常数n){
const fragment=document.createDocumentFragment();
用于(n.nodeValue.split(/(\s+/)的常数){
如果(s.trim()){
span.firstChild.nodeValue=s;
片段.appendChild(span.cloneNode(true));
}否则{
fragment.appendChild(document.createTextNode);
}
}
n、 replaceChild(片段,n);
}
}
因为我们可能要替换数千个节点,所以这段代码试图加快速度:它使用API、DOM克隆、通过简单的正则表达式跳过可能的超长空格序列和换行符序列,以及DocumentFragment将新节点放置在一个变异操作中。当然也不使用jQuery


另外,还有一些高级库用于更复杂的匹配和处理,如。

欢迎使用堆栈溢出。我不会使用
.text()
,因为它只读取元素的文本,而
.html()
将读取标记和文本。基本上,您需要迭代
的内容,找到每个单词(查找空格
“”
),并用
标记将它们包装起来。您还希望了解HTML元素,并且应该保留它们,但是这些元素的内容也应该以类似的方式包装

$(函数(){
函数包装(w){
返回“+w+”;
}
函数标记文字(str){
var html=$.parseHTML(str);
var节点=[];
$.each(html、函数(i、el){
nodes.push({
姓名:el.nodeName,
类型:el.nodeType,
内容:el.nodeValue,
元素:el
});
});
log(html,节点);
var部分=[];
变量t;
$.each(节点、函数(k、项){
如果(item.type==3){
t=item.content.trim().split(“”);
$。每个(t,函数(j,s){
零件推送(包装件);
});
}否则{
t=$(item.element).text().trim().split(“”);
$(item.element).html(“”);
$。每个(t,函数(j,s){
$(item.element).append(wrapWord+“”);
});
零件.push($(item.element).prop(“outerHTML”);
}
});
控制台日志(部件);
返回零件。连接(“”);
}
$($p.highlight”).html(markupText($($p.highlight”).prop(“innerHTML”));
});
p.突出显示跨度{
背景色:#FF0;
}

Lorem ipsum dolor sit amet,是一位杰出的献身者。但这是一种致命的疾病。埃涅阿斯·埃吉特·马克西姆斯·普鲁斯。请不要忘记过去,不要忘记过去。这是我的梦想,也是我的梦想。比本杜姆·维利特·波苏尔·森佩尔万岁


在所有情况下都能清楚地看到错误所在的位置,请使用accusantiumdoloremque laudantium

谢谢!我以前从未使用过TreeWalker API,但我尝试过您的解决方案,但它并不完全有效。
<p> 
    <span>Sed</span> 
    <span>ut</span> 
    <a> <span>perspiciatis</span> <span>unde</span> <span>omnis</span> </a>
    <span>iste</span> 
    <span>natus</span> 
    <em> <span>error</span> <span>sit</span> </em>
    <span>voluptatem</span> 
    <strong> <span>accusantium</span> </strong>
    <span>doloremque</span> 
    <span>laudantium</span> 
</p>

const span = document.createElement('span');
span.className = 'foo';
span.appendChild(document.createTextNode(''));

// these will display <span> as a literal text per HTML specification
const skipTags = ['textarea', 'rp'];

for (const p of document.getElementsByTagName('p')) {
  const walker = document.createTreeWalker(p, NodeFilter.SHOW_TEXT);
  // collect the nodes first because we can't insert new span nodes while walking
  const textNodes = [];
  for (let n; (n = walker.nextNode());) {
    if (n.nodeValue.trim() && !skipTags.includes(n.parentNode.localName)) {
      textNodes.push(n);
    }
  }
  for (const n of textNodes) {
    const fragment = document.createDocumentFragment();
    for (const s of n.nodeValue.split(/(\s+)/)) {
      if (s.trim()) {
        span.firstChild.nodeValue = s;
        fragment.appendChild(span.cloneNode(true));
      } else {
        fragment.appendChild(document.createTextNode(s));
      }
    }
    n.parentNode.replaceChild(fragment, n);
  }
}