什么是仅包装字符串的一部分的wrap方法?

时间:2015-10-27 08:37:36

标签: javascript jquery select highlight

我有这样的HTML:

<div>
     <h3>How are you? Fine?</h3>
</div>

我想在不同的东西中使用两个数字n和m来转换它,例如: 如果n = 5且m = 12

<div>
     <h3>How 
            <span class="yellow">are you?</span>
      Fine?</h3>
</div>

换句话说,我想使用两个数字“突出显示”字符串的一部分,这两个数字指定“突出显示”的开头和结尾(以字符为单位)。

我尝试了这个,但它不起作用:

//in the previous example it will be a xpath selector for div/h3
var selection=$(document.body).xpath(selector).text();

//it will be "are you?"
var substring=selection.substring(n,m);

//it would make that i want, but it doesn't
                                $(document.body).xpath(selector).contents().filter(function() {
                        return substring;
                    }).wrap("<span class=\"yellow\"></span>");
}

2 个答案:

答案 0 :(得分:1)

一种方法是 - 而不是换行,用切片操作版本替换h3的内容。

请参阅此JSFiddle http://jsfiddle.net/9LeL3f3n/21/

<div>
    <h3>How are you? Fine?</h3>
</div>


$(document).ready(function() {

    var highlight = function(str, start, end) {
      return str.slice(0,start-1) + 
        '<span style="color:#ffff00">' + 
        str.substring(start-1, end) + 
        '</span>' +  
        str.slice(-1 * (str.length - end));
    };

    var n = 5;
    var m = 12;

    $('h3').html(highlight($('h3').html(),n,m)); 

});

答案 1 :(得分:0)

我建议编写自己的插件来实现这一点,只是因为它似乎对重复使用有用。也就是说,我提供了以下方法,它有效地分割textNode节点,使用textNode.splitText()并在重新插入该节点之前将相关部分附加到创建的元素,并将textNodes包围回父元素: / p>

// a simple plugin approach, taken from:
// https://learn.jquery.com/plugins/basic-plugin-creation/
(function ($) {

    // defining the name of the plugin ('highlight'):
    $.fn.highlight = function (opts) {

        // the default settings, used if no arguments are
        // passed into the plugin via the 'opts' Object:
        var settings = {
            'start' : 0,
            'end' : 1,
            'wrapper' : 'span',
            'class' : 'highlight',
            'css' : {
                'color' : 'yellow'
            }
        },
            // 'empty' declared variables for later use:
            node, textMiddle, textEnd;

        // iterating over the 'opts' Object using
        // a for...in loop:
        for (var prop in opts) {

            // if the 'opts' Object has an own property 'prop'
            // (not one inherited from its prototype chain):
            if (opts.hasOwnProperty(prop)) {

                // we update the 'settings' Object to
                // be equal to the 'opts' Object property-value:
                settings[prop] = opts[prop];
            }
        }

        // using parseInt() to ensure that we're working
        // with numbers, rather than strings, and that those
        // numbers are in base-10:
        settings.start = parseInt(settings.start, 10);
        settings.end = parseInt(settings.end, 10);

        // normalising the settings.wrapper string, ensuring that
        // if the user passes in '<span>' (or '<<<<<span>', etc)
        // we remove those (this could be made even safer by only
        // allowing the first consecutive string of alphabetical
        // characters):
        settings.wrapper = settings.wrapper.replace(/<|>/g,'');

        // here we iterate over, and return, the jQuery collection
        // to allow for chaining to continue (here 'this' is the
        // jQuery collection of nodes/elements):
        return this.each(function () {

            // here this is the DOM node from the collection.

            // and here we iterate over the childNodes of each
            // DOM node from that collection:
            $(this).contents().each(function () {

                // if the current childNode is nodeType 3 (a textNode)
                // AND the length of the nodeValue (the text itself)
                // is greater than, or equal to, the settings.end:
                if (this.nodeType === 3 && this.nodeValue.length >= settings.end) {

                    // we create a new element equal to the
                    // settings.wrapper argument passed in by
                    // the user (or the default):
                    node = document.createElement(settings.wrapper);

                    // if we have a settings.css Object:
                    if (settings.css) {

                        // we iterate over that Object with a
                        // for...in loop (as above):
                        for (var prop in settings.css){
                            if (settings.css.hasOwnProperty(prop)) {

                                // setting the node's style property
                                // to be equal to the property-value
                                // of the settings.css Object:
                                node.style[prop] = settings.css[prop];
                            }
                        }
                    }

                    // if we have a settings.class:
                    if (settings.class) {

                        // we use Array.prototype.forEach
                        Array.prototype.forEach
                          // with Function.prototype.call()
                          // to iterate over the resulting array
                          // of splitting the settings.class
                          // String on white-space characters:
                          .call(settings.class.split(/\s+/),
                              // the 'classname' argument is the
                              // class-name from the string, now
                              // in the Array over which we're iterating:
                              function (classname) {

                                  // here we add the trimmed classname
                                  // string (removing the leading and
                                  // trailing white=space) to the
                                  // list of classes of the node:
                                  node.classList.add(classname.trim());
                              });
                    }

                    // here we split the textNode (this) using
                    // Text.splitText(offset); which converts
                    // one textNode into two separate textNodes
                    // and returns the second (newly-created) 
                    // textNode ('this' remains 'this' but with
                    // shortened text):
                    textMiddle = this.splitText(settings.start);

                    // and again, but this time we have to compensate
                    // for already shortening the textNode, and
                    // and so subtract the offset from the settings.end:
                    textEnd = textMiddle.splitText(settings.end - settings.start);

                    // appending the textNode to the created
                    // element:
                    node.appendChild(textMiddle);

                    // inserting the created node after the original
                    // textNode:                        
                    this.parentNode.insertBefore(node, this.nextSibling);


                }
            });

        });
    };

// passing jQuery into the plugin in order to allow us to use
// the $ alias within the plugin:
})(jQuery);

// using the plugin:
$('div h3').highlight({
    // setting the 'start' offset:
    'start' : 4,
    // the end index/offset:
    'end' : 12,
    // specifying classes to add to the created element(s):
    'class' : 'highlight classes',
    // setting the CSS properties of the created element(s):
    'css' : {
        'color' : '#f89',
        'text-decoration' : 'underline'
    }
});

(function($) {
  $.fn.highlight = function(opts) {
    var settings = {
        'start': 0,
        'end': 1,
        'wrapper': 'span',
        'class': 'highlight',
        'css': {
          'color': 'yellow'
        }
      },
      node, textMiddle, textEnd;

    for (var prop in opts) {
      if (opts.hasOwnProperty(prop)) {
        settings[prop] = opts[prop];
      }
    }

    settings.wrapper = settings.wrapper.replace(/<|>/g, '');

    return this.each(function() {

      $(this).contents().each(function() {
        if (this.nodeType === 3 && this.nodeValue.length >= settings.end) {
          node = document.createElement(settings.wrapper);

          if (settings.css) {
            for (var prop in settings.css) {
              if (settings.css.hasOwnProperty(prop)) {
                node.style[prop] = settings.css[prop];
              }
            }
          }

          if (settings.class) {
            Array.prototype.forEach.call(settings.class.split(/\s+/), function(classname) {
              node.classList.add(classname.trim());
            });
          }

          textMiddle = this.splitText(settings.start);
          textEnd = textMiddle.splitText(settings.end - settings.start);
          node.appendChild(textMiddle);

          this.parentNode.insertBefore(node, this.nextSibling);


        }
      });

    });
  };
})(jQuery);

$('div h3').highlight({
  'start': 4,
  'end': 12,
  'class': 'highlight classes',
  'css': {
    'color': '#f89',
    'text-decoration': 'underline'
  }
});
.highlight {
  font-style: italic;
}
.classes {
  font-variant: small-caps;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
  <h3>How are you? Fine?</h3>
</div>

外部JS Fiddle demo

参考文献: