如何使用jQuery为特定单词的所有实例中的部分内容添加样式?

8

不寻常的情况。我有一个客户,我们称之为“BuyNow”。他们希望在网站内容中出现的每个实例中,将他们的名称样式化为“BuyNow”,其中他们名称的后半部分为粗体。

我真的不想花一整天时间为所有内容添加标签。有没有一种使用jQuery的好方法来做到这一点?

我已经看到了jQuery的高亮插件,它非常接近,但我需要将单词的第二个部分加粗。


6
与其将它标记为强调,我认为你会希望将其设置为<span>,这样你就可以应用CSS来将其标记为强调、蓝色或其他颜色……不过这并不能回答你的jQuery问题;-) - SingleShot
@SingleShot - 同意,带有类的<span>标签将为您提供更多的灵活性。 - Russ Cam
1
是的,语义上来说,“Now”并没有强调的意思,除非你在说公司名称时真的大喊“现在!”这只是一种排版怪癖,使用<span>标签会更加合适。 - bobince
1
看一下mark.js,它可以为您完成这项工作。 - dude
5个回答

12
为了可靠地执行此操作,您需要遍历文档中的每个元素,查找文本节点并搜索其中的文本。(这就是问题中提到的插件所做的操作。)这里有一个使用纯JavaScript/DOM编写的代码示例,允许使用RegExp模式匹配。由于选择器只能选择元素,“:contains”选择器又是递归的,因此在这里jQuery帮助不大,无法提供太大的帮助。
// Find text in descendents of an element, in reverse document order
// pattern must be a regexp with global flag
//
function findText(element, pattern, callback) {
    for (var childi= element.childNodes.length; childi-->0;) {
        var child= element.childNodes[childi];
        if (child.nodeType==1) {
            findText(child, pattern, callback);
        } else if (child.nodeType==3) {
            var matches= [];
            var match;
            while (match= pattern.exec(child.data))
                matches.push(match);
            for (var i= matches.length; i-->0;)
                callback.call(window, child, matches[i]);
        }
    }
}

findText(document.body, /\bBuyNow\b/g, function(node, match) {
    var span= document.createElement('span');
    span.className= 'highlight';
    node.splitText(match.index+6);
    span.appendChild(node.splitText(match.index+3));
    node.parentNode.insertBefore(span, node.nextSibling);
});

4
正则表达式和replace()函数是常见的编程工具。例如:
var text = $([selector]).html();
text = text.replace(/Now/g,'<strong>Now<\strong>');
$([selector]).html(text);

使用html()来实现这一点需要注意。首先,有可能会替换<a>元素的href属性和其他属性中匹配的字符串,从而导致页面功能不正确。也许可以编写更好的正则表达式来克服一些潜在的问题,但性能可能会受到影响(我不是正则表达式专家)。其次,使用html()来替换内容将导致非可序列化数据(例如绑定到元素标记、表单数据等的事件处理程序)丢失。编写一个只针对文本节点的函数可能是更好/更安全的选择,这取决于页面的复杂程度。
如果您可以访问HTML文件,则如果内容是静态的,最好在文件中查找并替换他们想要更改外观的单词。NotePad++在文件中查找选项在大多数情况下都很有效。

按照SingleShot的建议,使用带有CSS类的<span>比使用<strong>元素更加灵活。


不要使用正则表达式解析HTML。<a href="BuyNow.html"> -> 哎呀。 - bobince
1
仅进行测试!另请注意,设置html()会丢失所有不可序列化的信息,例如事件处理程序、JavaScript 引用和表单数据。 - bobince
@bobince - 我会在答案中加入一些警告。最安全的方法可能是仅对文本节点进行操作,但我看到你已经在你的答案中涵盖了这个角度 :) - Russ Cam
你最好缓存元素而不是文本: var elem = $([selector]); elem.html(elem.html().replace(/Now/g,'<strong>Now<\strong>')); - Gumbo
最终内容将在CMS中,因此进行全局查找/替换(在我的情况下是Coda)不是我首选的解决方案,尽管我考虑过。我选择了另一种解决方案,仅仅是因为加粗的单词也经常在整个网站中使用,包括页面名称,所以这也不行。但还是谢谢。 :) - Ben Dyer

1

我写了一个小插件来实现这个功能。请看一下我对类似问题的答案

与下载被接受答案中建议的插件不同,我强烈建议您使用我编写的插件——它速度更快。


0
var Run=Run || {};

Run.makestrong= function(hoo, Rx){
 if(hoo.data){
  var X= document.createElement('strong');
  X.style.color= 'red'; // testing only, easier to spot changes
  var pa= hoo.parentNode;
  var res, el, tem;
  var str= hoo.data;
  while(str && (res= Rx.exec(str))!= null){
   var tem= res[1];
   el= X.cloneNode(true);
   el.appendChild(document.createTextNode(tem));
   hoo.replaceData(res.index, tem.length,'');
   hoo= hoo.splitText(res.index);
   str= hoo.data;
   if(str) pa.insertBefore(el, hoo);
   else{
    pa.appendChild(el);
    return;
   }
  }
 }
}

Run.godeep= function(hoo, fun, arg){
 var A= [];
 if(hoo){
  hoo= hoo.firstChild;
  while(hoo!= null){
   if(hoo.nodeType== 3){
    if(hoo.data) A[A.length]= fun(hoo, arg);
   }
   else A= A.concat(arguments.callee(hoo, fun, arg));
   hoo= hoo.nextSibling;
  }
 }
 return A;
}

//test

**Run.godeep(document.body, Run.makestrong,/([Ee]+)/g);**

0

这不是jQuery脚本,而是纯JavaScript,我相信它可以稍作修改。 链接


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接