javascript - Jquery在不使用split的情况下在div内的x个单词后插入html

标签 javascript jquery html regex

已经4天了,我试过很多不同的方法,现在我有点想放弃了,这似乎是不可能的事情......

我正在尝试创建一个脚本,它将生成一个 html 文本,并在它计算出 x 个单词后将其放入博客文章中,比方说在它计算出 10 个单词后。我能够通过使用正则表达式(拆分)来实现这一点,但正则表达式正在剥离我帖子的 HTML。理论上这很简单,但我不知道为什么在实践中如此复杂。我不能使用段落或任何元素作为引用,它必须仅在文本后插入 html,而不是在代码标签内,例如,我有 <script> some code </script> My blog text --- The text that needs to be inserted -- ,它不能计算脚本标签内的内容,它应该只计算纯文本并在其后插入新的 html 并呈现。假设这与使用 WYSIWG 编辑器输入文本和插入图像的逻辑相同。 真的很难解释。

基本上我需要的东西只是得到一个横幅并将其插入文本中 x 个单词之后,就这样。

这是我上次尝试的方法,但没有成功(代码无效):

<div style="width:1000px; margin-left:auto; margin-right:auto" class="newsitem_text">
    <div style="width:980px; margin-left:auto; margin-right:auto">
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec pellentesque urna eu pulvinar maximus. Sed elit nunc, vestibulum ut eros vitae, pellentesque rhoncus ipsum. In et metus non diam porttitor maximus iaculis nec lectus. Quisque sodales scelerisque auctor. Nam rutrum venenatis eros, eu condimentum erat placerat ut. Pellentesque sed tempus sem, eu viverra ipsum. Vestibulum nec turpis convallis, dapibus massa vitae, posuere mauris. Suspendisse mattis tincidunt lorem. Aliquam erat volutpat. Nullam at tincidunt erat, maximus laoreet ipsum.
    </div>
</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script>
    jQuery(function ($) {

        var wordList = $(".newsitem_text").html();
        var newHtml = ' ';

        $.each(wordList, function(index, word) {
            newHtml += ' ' + word;
            if (index == 2) {
                newHtml += '<img src="https://www.google.com.br/logos/doodles/2015/adolphe-saxs-201st-birthday-6443879796572160.2-res.png" />'     
            }        
        });

        $(newHtml).html('').insertAfter(".newsitem_text");
    });

</script>

更新 - 这是我开始在 stackoverflow 中打开有关此主题的主题时,我将提供链接以供引用:

最佳答案

下面是一种解决方法,尽管遗憾的是,它有点幼稚,而且我不禁怀疑它过于复杂。然而:

// a simple utility function to get only the actual words
// from the supplied textNode (though this should work for
// elements also):
function getActualWords(node) {

    // gets the textContent of the node,
    // splits that string on one-or-more ('+')
    // white-space characters ('\s');
    // filters the array returned by split():
    return node.textContent.split(/\s+/).filter(function (word) {
        // word is the current array-element
        // (a 'word') in the array over
        // which we're iterating using
        // Array.prototype.filter();
        // here if the word, with leading
        // and trailing white-space removed
        // (using String.prototype.trim())
        // has a length greater than 0
        // (a falsey value) the word is kept
        // in the array returned by filter:
        return word.trim().length;

        // note that negative numbers are
        // also truthy, but no string can
        // have a negative length; so the
        // comparison is effectively, if
        // not explicitly 'greater than zero'
        // rather than simply 'not-zero'
    });
}

// named function to insert the specified
// element after the nth word:
function insertElemAfterNthWord(opts) {

    // defining the defaults for the function
    // (which can be overridden via the opts
    // Object):
    var defaults = {

        // the word after-which to insert the
        // the new element:
        'nth': 5,

        // the text of the new element:
            'elemText': 'new element',

        // the type of element (note no '<' or '>'):
            'elemTag': 'div'
    };

    // iterating over the supplied opts Object to update
    // the defaults with the user-supplied options using
    // for...in loop:
    for (var prop in opts) {

        // if the opts Object has a property and
        // that property is not inherited from the
        // prototype chain:
        if (opts.hasOwnProperty(prop)) {

            // we set the defaults property
            // to the property-value held
            // in the opts Object:
            defaults[prop] = opts[prop];
        }
    }

    // aliasing the defaults object (simply to save
    // typing; this is not essential):
    var d = defaults,

        // ensuring that the supplied string,
        // specifying the element-type has no
        // '<' or '>' characters (to ensure validty
        // this should be extended further to
        // ensure only alphabetical characters are kept):
        tag = d.elemTag.replace(/<|>/g, ''),

        // creating the new element:
        elem = document.createElement(tag);

    // setting the textContent of the new element:
    elem.textContent = d.elemText;

    // ensuring that the d.nth variable is
    // a number, not a string, in base-10:
    d.nth = parseInt(d.nth, 10);

    // if a node was specified:
    if (d.node) {

        // setting the 'n' variable to hold
        // to the firstChild of the d.node:
        var n = d.node.firstChild,

            // using the utility function (above)
            // to get an Array of only the actual 
            // words held in the node:
            words = getActualWords(n),

            // getting the number of words held
            // in the Array of words:
            wordCount = words.length;

        // while (n.nodeType is not a textNode OR
        // d.nth is a greater number than the number
        // of words in the node) AND the node has
        // a following sibling node:
        while ((n.nodeType !== 3 || d.nth > wordCount) && n.nextSibling) {

            // we update n to the next-sibling:
            n = n.nextSibling;

            // we get an array of words from
            // newly-assigned node:
            words = getActualWords(n);

            // we update the wordCount, in
            // order to progress through:
            wordCount = words.length;
        }

        // if the number of words is less than
        // the nth word after which we want to
        // insert the element, we return from
        // the function (doing nothing):
        if (getActualWords(n).length < d.nth) {
            return;

        // otherwise:
        } else {

            // again we get an Array of actual words,
            // we slice that Array and then get the
            // last array-element from that array,
            // using Array.prototype.pop():
            var w = getActualWords(n).slice(0, d.nth).pop(),

                // here we get the index of that word
                // (note that this is naive, and relies
                // upon the word being unique as a
                // proof-of-concept; I plan to update later):
                i = n.textContent.indexOf(w);

                // we split the n textNode into
                // two separate textNodes, at
                // supplied index ('i + w.length');
                // n remains the shortened 'first'
                // textNode:
                n.splitText(i + w.length);

            // navigating to the parentNode, and
            // using insertBefore() to insert the
            // new element ('elem') before the
            // next-siblin of the n textNode:
            n.parentNode.insertBefore(elem, n.nextSibling);

            // doing exactly the same, but adding a
            // newly-created textNode (of a space character)
            // between the 'n' textNode (which by definition
            // ends without a space) and newly-inserted
            // element:
            n.parentNode.insertBefore(document.createTextNode(' '), n.nextSibling);

            // joining adjacent, but unconnected,
            // textNodes (n and the newly-inserted
            // space character) together, to become
            // a single node:
            n.parentNode.normalize();

            // returning the newly-created element
            // so that it can be modified if required
            // or simply cached:
            return elem;
        }

    }
}


// calling the function, specifying the
// user-defined properties:
insertElemAfterNthWord({
    // after the tenth word:
    'nth': 10,
    // the element-type (a span):
        'elemTag': 'span',

    // setting the text of that new element:
        'elemText': 'this is the newly-added text inside the newly-added element!',

    // specifying the node into which the element
    // should inserted:
        'node': document.querySelector('div > div')

// chaining the function, to use the Element.classList
// API to add the 'newlyAdded' class to the
// newly-created element:
}).classList.add('newlyAdded');

function getActualWords(node) {
  return node.textContent.split(/\s+/).filter(function(word) {
    return word.trim().length;
  });
}

function insertElemAfterNthWord(opts) {
  var defaults = {
    'nth': 5,
    'elemText': 'new element',
    'elemTag': 'div'
  };

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

  var d = defaults,
    tag = d.elemTag.replace(/<|>/g, ''),
    elem = document.createElement(tag);

  elem.textContent = d.elemText;

  d.nth = parseInt(d.nth, 10);

  if (d.node) {
    var n = d.node.firstChild,
      words = getActualWords(n),
      wordCount = words.length;

    while ((n.nodeType !== 3 || d.nth > wordCount) && n.nextSibling) {

      n = n.nextSibling;
      words = getActualWords(n);
      wordCount = words.length;
    }
    if (getActualWords(n).length < d.nth) {
      return;
    } else {
      var w = getActualWords(n).slice(0, d.nth).pop(),
        i = n.textContent.indexOf(w);
      n.splitText(i + w.length);
      n.parentNode.insertBefore(elem, n.nextSibling);
      n.parentNode.insertBefore(document.createTextNode(' '), n.nextSibling);
      n.parentNode.normalize();

      return elem;
    }

  }
}


insertElemAfterNthWord({
  'nth': 10,
  'elemTag': 'span',
  'elemText': 'this is the newly-added text inside the newly-added element!',
  'node': document.querySelector('div > div')
}).classList.add('newlyAdded');
span {
  color: #f90;
}
div {
  margin-left: auto;
  margin-right: auto;
}
.newlyAdded {
  background-color: #ffa;
}
<div class="newsitem_text">
  <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec pellentesque urna eu pulvinar maximus. Sed elit nunc, vestibulum ut eros vitae, pellentesque rhoncus ipsum. In et metus non diam porttitor maximus iaculis nec lectus. Quisque sodales scelerisque
    auctor. Nam rutrum venenatis eros, eu condimentum erat placerat ut. Pellentesque sed tempus sem, eu viverra ipsum. Vestibulum nec turpis convallis, dapibus massa vitae, posuere mauris. Suspendisse mattis tincidunt lorem. Aliquam erat volutpat. Nullam
    at tincidunt erat, maximus laoreet ipsum.</div>

JS Fiddle demo .

上述方法的注意事项:

  • 它要求所有的单词都保存在一个文本节点中;它甚至不会尝试计算可能从一个元素开始并在同级元素内结束的单词。
  • 在当前的实现中,它不允许以任何方式将非文本插入到创建的元素中(尽管这可以通过使用 elem.innerHTML 代替 elem.textContent),但它确实将创建的元素返回到调用上下文,因此它可以被缓存或链接,这允许以某些方式操作该创建的元素。
  • 有些检查(如果不是大部分的话)非常幼稚;并将受益于扩展以解决您自己的特定边缘情况。

引用资料:

关于javascript - Jquery在不使用split的情况下在div内的x个单词后插入html,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33588235/

相关文章:

javascript - 如何在最后一张幻灯片后停止动画?

javascript - Svelte 绑定(bind)选择值未在获取时更新

JavaScript:从 JavaScript 调用 anchor 标记的点击事件

javascript - 如何延迟按键输入

javascript - 具有相同状态名称的多个组件,在点击父 div 时更改一个而不影响其他组件?

javascript - 如何将 div 元素移动到另一个 div 元素内?

javascript - 垂直对齐图像 hover img

javascript - 在 Javascript 中加载 XML 数据时出错

javascript - 如何在 jQuery 中控制我的悬停事件?

javascript - 在 FBJS/Facebook 中使用 getElementById().getValue 的问题!