jQuery:wrapAll()在保留空格的同时跨越元素

时间:2016-09-05 13:36:13

标签: jquery jquery-selectors jquery-events

我有一个文字,每个单词都包含一个span元素,以使它们可以点击。我希望能够通过单击要突出显示的第一个和最后一个单词来突出显示文本的一部分,然后单击一个单独的按钮来执行突出显示(即,在所选的第一个和最后一个单词之间包括每个单词)。在突出显示的部分后面还会添加注释。我已经取得了进步并且已经完成了这一部分:

HTML:

<div id="textbox">
<span>Foo</span> <span>foo</span> <span>foo</span> <span>foo</span> 
<span>foo</span> <span>foo</span> <span>foo</span> <span>foo</span> 
<span>foo</span> <span>foo</span> <span>foo</span> <span>foo</span>.
</div>
<input id="commentbox" placeholder="Type your comment here"> 
<button id="exechighlight" value="Highlight">

JavaScript:

$('#textbox > span').click(function() {
  $(this).addClass('selected');
});

$('#exechighlight').click(function(){
if($('#commentbox').val() !== '') {
  $('.selected').filter(":last").after(' <span class="comment">' + $('#commentbox').val() + '</span>');
} else {
  $('.selected').filter(':last').after(' <span class="comment">Default comment</span>');
}
$('.selected').filter(":first").nextUntil('.comment').andSelf().wrapAll('<span class="highlight">');
$('.selected').removeClass('selected');
$('#commentbox').val('');
});

我可以很好地包装东西,但wrapAll()似乎没有保留包裹的span元素之间的空格。我尝试使用CSS,但无济于事:

.highlight {
  background-color: #f00; 
  white-space: pre-wrap; 
  white-space: -moz-pre-wrap;
}

如何进行?我也需要能够撤消突出显示,即打开<span class='highlight'>并保留原始间距。

2 个答案:

答案 0 :(得分:0)

  

wrapAll()似乎没有保留已包装的span元素

之间的空格

实际上它不应该,因为它们不在jQuery集中,你说你想要包装。 nextUntil只查看元素,而不是文本节点。

您需要自己构建jQuery集,包括跨度之间的文本节点。见评论:

$("#btn").on("click", function() {
  // Find the selected span
  var sel = $(".selected");
  
  // Find the comment span (raw, no jQuery wrapper)
  var comment = sel.siblings(".comment")[0];
  
  // Gather up all nodes (including text nodes) following it, up until the comment element
  var node = sel[0];
  var nodes = [];
  while (node && node !== comment) {
    nodes.push(node);
    node = node.nextSibling;
  }
  
  // Disregard final text node if any
  if (nodes.length && nodes[nodes.length - 1].nodeType === 3) {
    --nodes.length;
  }
  
  // Get a jQuery set for them, and wrap it
  $(nodes).wrapAll("<span class='wrapper'></span>");
});
.wrapper {
  border: 1px solid red;
}
<div>
  <span class="selected">one</span>
  <span>two</span>
  <span>three</span>
  <span class="comment">The comment</span>
</div>
<input type="button" id="btn" value="Click Me">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

答案 1 :(得分:0)

nextUntil() 方法不包含textnode。您还需要在jQuery中使用 contents() 方法获取textNode

&#13;
&#13;
$('#textbox > span').click(function() {
  $(this).addClass('selected');
});

$('#exechighlight').click(function() {
  if ($('#commentbox').val() !== '') {
    $('.selected').filter(":last").after(' <span class="comment">' + $('#commentbox').val() + '</span>');
  } else {
    $('.selected').filter(':last').after(' <span class="comment">Default comment</span>');
  }
  getAllNode($('.selected').filter(":first").nextUntil('.comment').andSelf()).wrapAll('<span class="highlight">');
  $('.selected').removeClass('selected');
  $('#commentbox').val('');
});

// method for getting the element which also includes textnode
function getAllNode($sel) {
  // get the first element from selector
  var $first = $sel.first(),
    // get the last element from selector
    $last = $sel.last(),
    // flag variable for filter method
    match = false;
  // get all nodes includes text node of it's parent
  return $sel.parent().contents().filter(function() {
    // filter out element eleemnt in between the first and last including the first and last
    if ($(this).is($first) || $(this).is($last)) {
      match = !match;
      return true;
    }
    return match;
  });
}
&#13;
.highlight {
  background-color: #f00;
  white-space: pre-wrap;
  white-space: -moz-pre-wrap;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="textbox">
  <span>Foo</span>  <span>foo</span>  <span>foo</span>  <span>foo</span> 
  <span>foo</span>  <span>foo</span>  <span>foo</span>  <span>foo</span> 
  <span>foo</span>  <span>foo</span>  <span>foo</span>  <span>foo</span>.
</div>
<input id="commentbox" placeholder="Type your comment here">
<button id="exechighlight" value="Highlight">
&#13;
&#13;
&#13;