使用JavaScript/JQuery替换元素前的文本部分

3
我有一串带有t标签的文字,其中一些单词之前带有t标签。在t标签内部是单词之前的id,我需要查找并将其替换为一些html代码。到目前为止,我的解决方案似乎过于复杂,而且也无法正常工作,因为替换后的html被打印为文本而不是html。是否有更好、更简单和可行的解决方案呢?
JSFiddle: https://jsfiddle.net/fsdx2o7h/18/
This is the first<t>element1</t>. This is the second<t>element2</t>. This is the third<t>element3</t>.

$('t').each(function() {
        var prevText = this.previousSibling.nodeValue;
        var arrPrevText = prevText.split(' ');
        var nrElements = arrPrevText.length;
        var textpart = arrPrevText[nrElements-1];
        var id = $(this).html();
        arrPrevText[nrElements-1] = "<span id='" + id + "'>" + textpart + "</span>";
        this.previousSibling.nodeValue = arrPrevText.join(' ');
    });


我认为你想用<span id="1">element</span>替换element1。是这样吗? - Mohammad
不完全正确,element1 应该是在开头 t 标签之前的文本部分的 id。 - clausnz
2个回答

1

它可以更简单一些,但你走在了正确的道路上。请看注释:

$('t').each(function() {
  // Get our previous sibling
  var prev = this.previousSibling;
  // If not a text node, quit
  if (prev.nodeType !== 3) {
    return;
  }
  // Get the text of it
  var text = prev.nodeValue;
  // Find the last word; if none, quit
  var index = text.lastIndexOf(" ");
  if (index < 0){
    return;
  }
  // Skip past the space prior to the word
  ++index;
  // Grab the word
  var word = text.substring(index).trim();
  // Remove it from the text node
  prev.nodeValue = text.substring(0, index);
  // Replace this `t` element with a span using
  // the word as its text and this `t` element's
  // innerHTML as its ID
  $(this).replaceWith(
    $("<span>").text(word).attr("id", this.innerHTML)
  );
});
span[id] {
  color: red;
}
This is the first<t>element1</t>. This is the second<t>element2</t>. This is the third<t>element3</t>.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


1

虽然您已经接受了一个答案,但我认为我可以提供一个稍微简单一些的替代方案(请注意,我不确定是否应该删除<t>元素):

// selecting the <t> elements, and using the before()
// method to insert new contents ahead of each of the
// elements in the collection:
$('t').before(function() {

  // caching the 'this' (the current <t> element):
  var cached = this,

    // finding the previous sibling of the current
    // <t> element:
    prevNode = cached.previousSibling,

    // splitting that previous textNode (without first
    // checking that it is a textNode, this will lead
    // to errors in live code if you're working with
    // unanticipated structures) into two textNodes
    // at the index of the last index of a white-space,
    // adding 1 to that index in order that we get the
    // last word, without the space character, into its
    // own textNode:
    newPrevNode = prevNode.splitText(prevNode.nodeValue.lastIndexOf(' ') + 1),

    // creating a <span> element:
    span = document.createElement('span');

  // setting the id of the new <span> element to the
  // text of the current <t> element, after first
  // removing leading and trailing white-space
  // using String.prototype.trim():
  span.id = cached.textContent.trim();

  // appending the newPrevNode to the <span>:
  span.appendChild(newPrevNode);

  // returning the created <span> to the method for
  // insertion ahead of the current <t> element:
  return span;

// I'm unsure if you want to remove the <t> elements, if
// you do we can do that using the remove() method (the
// before() method returns the original collection, not
// the newly-inserted elements); if you don't want to
// remove the <t> elements simply omit the call to remove():
}).remove();

$('t').before(function() {
  var cached = this,
    prevNode = cached.previousSibling,
    newPrevNode = prevNode.splitText(prevNode.nodeValue.lastIndexOf(' ') + 1),
    span = document.createElement('span');

  span.id = cached.textContent.trim();
  span.appendChild(newPrevNode);

  return span;

}).remove();
span {
  color: #f90;
}
span::after {
  content: ' (#' attr(id)') ';
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
This is the first
<t>element1</t>. This is the second
<t>element2</t>. This is the third
<t>element3</t>.

JS Fiddle演示

上述方法使用了相对较少的jQuery,但仍需要jQuery;以下是一个纯JavaScript的替代方案:

// converting the NodeList returned by document.querySelectorAll() into
// an Array, using Array.from(); and iterating over that Array of <t>
// elements using Array.prototype.forEach():
Array.from(document.querySelectorAll('t')).forEach(function(elem) {
  // 'elem' : a reference to the current array-element of the
  //          array over which we're iterating.

  // caching that array-element (partially this is laziness since it
  // meant I could assign the variable here and not have to change
  // 'cached' to 'elem' in copying from the above jQuery snippet):
  var cached = elem,

    // retrieving the previousSibling, the textNode:
    prevNode = cached.previousSibling,

    // splitting that textNode into two textNodes at the index,
    // plus one, of the last white-space character; this returns
    // the newly-created textNode (the one 'broken off' from the
    // existing textNode):
    newPrevNode = prevNode.splitText(prevNode.nodeValue.lastIndexOf(' ') + 1),

    // creating a <span> element:
    span = document.createElement('span');

  // setting the id of the <span> to the text of the
  // current <t> element, after first removing
  // leading and trailing white-space using
  // String.prototype.trim():
  span.id = cached.textContent.trim();

  // appending the newly-created/'broken off'
  // textNode to the <span>:
  span.appendChild(newPrevNode);

  // using Node.insertBefore() to insert the
  // <span> ahead of the current <t> element:
  cached.parentNode.insertBefore(span, cached);

  // using Node.removeChild() to remove the
  // current <t> element from the DOM; again:
  // omit this line if you wish to retain
  // the <t> elements in the DOM:
  cached.parentNode.removeChild(cached);

});

Array.from(document.querySelectorAll('t')).forEach(function(elem) {
  var cached = elem,
    prevNode = cached.previousSibling,
    newPrevNode = prevNode.splitText(prevNode.nodeValue.lastIndexOf(' ') + 1),
    span = document.createElement('span');

  span.id = cached.textContent.trim();
  span.appendChild(newPrevNode);

  cached.parentNode.insertBefore(span, cached);

  cached.parentNode.removeChild(cached);

});
span {
  color: #f90;
}
span::after {
  content: ' (#' attr(id)') ';
}
This is the first
<t>element1</t>. This is the second
<t>element2</t>. This is the third
<t>element3</t>.

JS Fiddle演示

参考文献:


很棒的解决方案,David!也许是迄今为止最详细的一个。我会在接下来的几天尝试使用纯JavaScript替代方案,这可能是最快的一个。 - clausnz
1
我很高兴能够帮助!请记住,纯JavaScript解决方案使用了es6方法Array.from(),这可能会对使用旧浏览器的用户造成问题。 - David Thomas

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