Wrap tags around http text

前端 未结 3 906
感动是毒
感动是毒 2020-11-27 07:35

How do I find every word on a page beginning with http:// and wrap tags around it?

Can I use something like regex perhaps?

3条回答
  •  清酒与你
    2020-11-27 08:13

    This is one of those few things that jQuery doesn't directly help you with much. You basically have to walk through the DOM tree and examine the text nodes (nodeType === 3); if you find a text node containing the target text you want to wrap ("http://.....", whatever rules you want to apply), you then split the text node (using splitText) into three parts (the part before the string, the part that is the string, and the part following the string), then put the a element around the second of those.

    That sounds a bit complicated, but it isn't really all that bad. It's just a recursive descent walker function (for working through the DOM), a regex match to find the things you want to replace, and then a couple of calls to splitText, createElement, insertBefore, appendChild.

    Here's an example that searches for a fixed string; just add your regex matching for "http://":

    walk(document.body, "foo");
    
    function walk(node, targetString) {
      var child;
    
      switch (node.nodeType) {
        case 1: // Element
          for (child = node.firstChild;
               child;
               child = child.nextSibling) {
            walk(child, targetString);
          }
          break;
    
        case 3: // Text node
          handleText(node, targetString);
          break;
      }
    }
    
    function handleText(node, targetString) {
      var start, targetNode, followingNode, wrapper;
    
      // Does the text contain our target string?
      // (This would be a regex test in your http://... case)
      start = node.nodeValue.indexOf(targetString);
      if (start >= 0) {
        // Split at the beginning of the match
        targetNode = node.splitText(start);
    
        // Split at the end of the match
        followingNode = targetNode.splitText(targetString.length);
    
        // Wrap the target in an element; in this case, we'll
        // use a `span` with a class, but you'd use an `a`.
        // First we create the wrapper and insert it in front
        // of the target text.
        wrapper = document.createElement('span');
        wrapper.className = "wrapper";
        targetNode.parentNode.insertBefore(wrapper, targetNode);
    
        // Now we move the target text inside it
        wrapper.appendChild(targetNode);
    
        // Clean up any empty nodes (in case the target text
        // was at the beginning or end of a text ndoe)
        if (node.nodeValue.length == 0) {
          node.parentNode.removeChild(node);
        }
        if (followingNode.nodeValue.length == 0) {
          followingNode.parentNode.removeChild(followingNode);
        }
      }
    }
    

    Live example


    Update: The above didn't handle it if there were multiple matches in the same text node (doh!). And oh what the heck, I did a regexp match — you will have to adjust the regexp, and probably do some post-processing on each match, because what's here is too simplistic. But it's a start:

    // The regexp should have a capture group that
    // will be the href. In our case below, we just
    // make it the whole thing, but that's up to you.
    // THIS REGEXP IS ALMOST CERTAINLY TOO SIMPLISTIC
    // AND WILL NEED ADJUSTING (for instance: what if
    // the link appears at the end of a sentence and
    // it shouldn't include the ending puncutation?).
    walk(document.body, /(http:\/\/[^ ]+)/i);
    
    function walk(node, targetRe) {
      var child;
    
      switch (node.nodeType) {
        case 1: // Element
          for (child = node.firstChild;
               child;
               child = child.nextSibling) {
            walk(child, targetRe);
          }
          break;
    
        case 3: // Text node
          handleText(node, targetRe);
          break;
      }
    }
    
    function handleText(node, targetRe) {
      var match, targetNode, followingNode, wrapper;
    
      // Does the text contain our target string?
      // (This would be a regex test in your http://... case)
      match = targetRe.exec(node.nodeValue);
      if (match) {
        // Split at the beginning of the match
        targetNode = node.splitText(match.index);
    
        // Split at the end of the match.
        // match[0] is the full text that was matched.
        followingNode = targetNode.splitText(match[0].length);
    
        // Wrap the target in an `a` element.
        // First we create the wrapper and insert it in front
        // of the target text. We use the first capture group
        // as the `href`.
        wrapper = document.createElement('a');
        wrapper.href = match[1];
        targetNode.parentNode.insertBefore(wrapper, targetNode);
    
        // Now we move the target text inside it
        wrapper.appendChild(targetNode);
    
        // Clean up any empty nodes (in case the target text
        // was at the beginning or end of a text ndoe)
        if (node.nodeValue.length == 0) {
          node.parentNode.removeChild(node);
        }
        if (followingNode.nodeValue.length == 0) {
          followingNode.parentNode.removeChild(followingNode);
        }
    
        // Continue with the next match in the node, if any
        match = followingNode
          ? targetRe.exec(followingNode.nodeValue)
          : null;
      }
    }
    

    Live example

提交回复
热议问题