为什么单击时 link 会从 DOM 中删除而不只是更改 textContent?

Why does a link gets removed from the DOM when clicked instead of just changing textContent?

有多个“阅读更多”link通过 JS 注入到 HTML。文本被截断,单击“阅读更多”会显示它,但由于某种原因,link 文本没有更改为“关闭”,link 从 DOM 中消失了。不明白为什么。

这会将 link 附加到文章元素:

s.content[index].appendChild(readMoreLink, s.content[index]);

有人可以看看并告诉我单击 link 时出现了什么问题,它从 DOM 中删除了吗?

var ReadMore = (function() {
  var s;

  return {
    settings: function() {
      return {
        content: document.querySelectorAll('.js-read-more'),
        originalContentArr: [],
        truncatedContentArr: [],
        moreLink: 'Read More',
        lessLink: 'Close',
      };
    },

    init: function() {
      s = this.settings();
      this.bindEvents();
    },

    bindEvents: function() {
      ReadMore.truncateText();
    },

    /**
     * Count Words
     * Helper to handle word count.
     * @param {string} str - Target content string.
     */
    countWords: function(str) {
      return str.split(/\s+/).length;
    },

    /**
     * Ellpise Content
     * @param {string} str - content string.
     * @param {number} wordsNum - Number of words to show before truncation.
     */
    ellipseContent: function(str, wordsNum) {
      return str.split(/\s+/).slice(0, wordsNum).join(' ') + '...';
    },

    /**
     * Truncate Text
     * Truncate and ellipses contented content
     * based on specified word count.
     * Calls createLink() and handleClick() methods.
     *
     */
    truncateText: function() {
      for (var i = 0; i < s.content.length; i++) {
        //console.log(s.content)
        var originalContent = s.content[i].innerHTML;
        var numberOfWords = s.content[i].dataset.rmWords;
        var truncateContent = ReadMore.ellipseContent(
          originalContent,
          numberOfWords,
        );
        var originalContentWords = ReadMore.countWords(originalContent);

        s.originalContentArr.push(originalContent);
        s.truncatedContentArr.push(truncateContent);

        if (numberOfWords < originalContentWords) {
          s.content[i].innerHTML = s.truncatedContentArr[i];
          var self = i;
          ReadMore.createLink(self);
        }
      }
      ReadMore.handleClick(s.content);
    },

    /**
     * Create Link
     * Creates and Inserts Read More Link
     * @param {number} index - index reference of looped item
     */
    createLink: function(index) {
      var readMoreLink = document.createElement('a');
      readMoreLink.setAttribute('id', `read-more_${index}`);
      readMoreLink.setAttribute('class', 'btn-more');
      readMoreLink.textContent = `${s.moreLink}`;

      s.content[index].appendChild(readMoreLink, s.content[index]);
    },

    /**
     * Handle Click
     * Toggle Click eve
     */
    handleClick: function(el) {
      var readMoreLink = document.querySelectorAll('.btn-more');

      for (var j = 0, l = readMoreLink.length; j < l; j++) {
        readMoreLink[j].addEventListener('click', function() {
          var moreLinkID = this.getAttribute('id');
          var index = moreLinkID.split('_')[1];

          el[index].classList.toggle('is-expanded');

          if (this.dataset.clicked !== 'true') {
            el[index].innerHTML = s.originalContentArr[index];
            this.textContent = s.lessLink;
            this.dataset.clicked = true;

            console.log(this.textContent);
          } else {
            el[index].innerHTML = s.truncatedContentArr[index];
            this.textContent = s.moreLink;
            this.dataset.clicked = false;
          }
          console.log(this);
        });
      }
    },

    /**
     * Open All
     * Method to expand all instances on the page.
     */
    openAll: function() {
      el = document.querySelectorAll('.btn-more');
      for (var i = 0; i < el.length; i++) {
        content[i].innerHTML = s.truncatedContentArr[i];
        el[i].innerHTML = s.moreLink;
      }
    },
  };
})();

ReadMore.init();
<main id="about">
  <div class="article js-read-more" data-rm-words="10">
    <h2>What are "Goals"?</h2>
    <p>Autem neque consequuntur sunt accusantium itaque at eum sed consectetur corporis culpa odit ratione, quam commodi provident quae, placeat voluptatum, debitis aspernatur nisi quibusdam?</p>
    <p>Autem neque consequuntur sunt accusantium itaque at eum sed consectetur corporis culpa odit ratione, quam commodi provident quae, placeat voluptatum, debitis aspernatur nisi quibusdam?</p>
  </div>

  <div class="article js-read-more" data-rm-words="10">
    <h2>Influences</h2>
    <p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Aspernatur, nesciunt tempore voluptates, deserunt ab earum magnam asperiores mollitia repellat praesentium optio cum ex cupiditate quasi quas? Autem neque consequuntur sunt accusantium itaque
      at eum sed consectetur corporis culpa odit ratione, quam commodi provident quae, placeat voluptatum, debitis aspernatur nisi quibusdam?</p>
    <p>Autem neque consequuntur sunt accusantium itaque at eum sed consectetur corporis culpa odit ratione, quam commodi provident quae, placeat voluptatum, debitis aspernatur nisi quibusdam?</p>
  </div>
</main>

为什么 link 被删除了?因为当单击“阅读更多”link

时,您要替换整个 innerHTML(包括按钮本身)

当您截断文本时,您会将整个 innerHTML 元素替换为 class“js-read-more”,将其替换为截断的文本和阅读更多按钮。

if (numberOfWords < originalContentWords) {
   s.content[i].innerHTML = s.truncatedContentArr[i];
   var self = i;
   ReadMore.createLink(self);
}

单击该按钮时,您执行相反的操作

 el[index].innerHTML = s.originalContentArr[index];

这具有完全删除按钮的效果。因此,下面一行更改为“显示较少”的文本完全没有意义。

要解决此问题,您需要做的就是确保在替换 handleClick

中的 innerHTML 后调用 el[index].append(this);

var ReadMore = (function() {
  var s;

  return {
    settings: function() {
      return {
        content: document.querySelectorAll('.js-read-more'),
        originalContentArr: [],
        truncatedContentArr: [],
        moreLink: 'Read More',
        lessLink: 'Close',
      };
    },

    init: function() {
      s = this.settings();
      this.bindEvents();
    },

    bindEvents: function() {
      ReadMore.truncateText();
    },

    /**
     * Count Words
     * Helper to handle word count.
     * @param {string} str - Target content string.
     */
    countWords: function(str) {
      return str.split(/\s+/).length;
    },

    /**
     * Ellpise Content
     * @param {string} str - content string.
     * @param {number} wordsNum - Number of words to show before truncation.
     */
    ellipseContent: function(str, wordsNum) {
      return str.split(/\s+/).slice(0, wordsNum).join(' ') + '...';
    },

    /**
     * Truncate Text
     * Truncate and ellipses contented content
     * based on specified word count.
     * Calls createLink() and handleClick() methods.
     *
     */
    truncateText: function() {
      for (var i = 0; i < s.content.length; i++) {
        //console.log(s.content)
        var originalContent = s.content[i].innerHTML;
        var numberOfWords = s.content[i].dataset.rmWords;
        var truncateContent = ReadMore.ellipseContent(
          originalContent,
          numberOfWords,
        );
        var originalContentWords = ReadMore.countWords(originalContent);

        s.originalContentArr.push(originalContent);
        s.truncatedContentArr.push(truncateContent);

        if (numberOfWords < originalContentWords) {
          s.content[i].innerHTML = s.truncatedContentArr[i];
          var self = i;
          ReadMore.createLink(self);
        }
      }
      ReadMore.handleClick(s.content);
    },

    /**
     * Create Link
     * Creates and Inserts Read More Link
     * @param {number} index - index reference of looped item
     */
    createLink: function(index) {
      var readMoreLink = document.createElement('a');
      readMoreLink.setAttribute('id', `read-more_${index}`);
      readMoreLink.setAttribute('class', 'btn-more');
      readMoreLink.textContent = `${s.moreLink}`;

      s.content[index].appendChild(readMoreLink, s.content[index]);
    },

    /**
     * Handle Click
     * Toggle Click eve
     */
    handleClick: function(el) {
      var readMoreLink = document.querySelectorAll('.btn-more');

      for (var j = 0, l = readMoreLink.length; j < l; j++) {
        readMoreLink[j].addEventListener('click', function() {
          var moreLinkID = this.getAttribute('id');
          var index = moreLinkID.split('_')[1];

          el[index].classList.toggle('is-expanded');

          if (this.dataset.clicked !== 'true') {
            el[index].innerHTML = s.originalContentArr[index];
            this.textContent = s.lessLink;
            this.dataset.clicked = true;            
            console.log(this.textContent);
          } else {
            el[index].innerHTML = s.truncatedContentArr[index];
            this.textContent = s.moreLink;
            this.dataset.clicked = false;
          }
          el[index].append(this);
          console.log(this);
        });
      }
    },

    /**
     * Open All
     * Method to expand all instances on the page.
     */
    openAll: function() {
      el = document.querySelectorAll('.btn-more');
      for (var i = 0; i < el.length; i++) {
        content[i].innerHTML = s.truncatedContentArr[i];
        el[i].innerHTML = s.moreLink;
      }
    },
  };
})();

ReadMore.init();
<main id="about">
  <div class="article js-read-more" data-rm-words="10">
    <h2>What are "Goals"?</h2>
    <p>Autem neque consequuntur sunt accusantium itaque at eum sed consectetur corporis culpa odit ratione, quam commodi provident quae, placeat voluptatum, debitis aspernatur nisi quibusdam?</p>
    <p>Autem neque consequuntur sunt accusantium itaque at eum sed consectetur corporis culpa odit ratione, quam commodi provident quae, placeat voluptatum, debitis aspernatur nisi quibusdam?</p>
  </div>

  <div class="article js-read-more" data-rm-words="10">
    <h2>Influences</h2>
    <p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Aspernatur, nesciunt tempore voluptates, deserunt ab earum magnam asperiores mollitia repellat praesentium optio cum ex cupiditate quasi quas? Autem neque consequuntur sunt accusantium itaque
      at eum sed consectetur corporis culpa odit ratione, quam commodi provident quae, placeat voluptatum, debitis aspernatur nisi quibusdam?</p>
    <p>Autem neque consequuntur sunt accusantium itaque at eum sed consectetur corporis culpa odit ratione, quam commodi provident quae, placeat voluptatum, debitis aspernatur nisi quibusdam?</p>
  </div>
</main>

我不确定以下是解决此问题的最佳方法,但希望它能说明 el[index].innerHTML = s.originalContentArr[index]; 正在从内容中删除 link。

var ReadMore = (function() {
  var s;

  return {
    settings: function() {
      return {
        content: document.querySelectorAll('.js-read-more'),
        originalContentArr: [],
        truncatedContentArr: [],
        moreLink: 'Read More',
        lessLink: 'Close',
      };
    },

    init: function() {
      s = this.settings();
      this.bindEvents();
    },

    bindEvents: function() {
      ReadMore.truncateText();
    },

    /**
     * Count Words
     * Helper to handle word count.
     * @param {string} str - Target content string.
     */
    countWords: function(str) {
      return str.split(/\s+/).length;
    },

    /**
     * Ellpise Content
     * @param {string} str - content string.
     * @param {number} wordsNum - Number of words to show before truncation.
     */
    ellipseContent: function(str, wordsNum) {
      return str.split(/\s+/).slice(0, wordsNum).join(' ') + '...';
    },

    /**
     * Truncate Text
     * Truncate and ellipses contented content
     * based on specified word count.
     * Calls createLink() and handleClick() methods.
     *
     */
    truncateText: function() {
      for (var i = 0; i < s.content.length; i++) {
        //console.log(s.content)
        var originalContent = s.content[i].innerHTML;
        var numberOfWords = s.content[i].dataset.rmWords;
        var truncateContent = ReadMore.ellipseContent(
          originalContent,
          numberOfWords,
        );
        var originalContentWords = ReadMore.countWords(originalContent);

        s.originalContentArr.push(originalContent);
        s.truncatedContentArr.push(truncateContent);

        if (numberOfWords < originalContentWords) {
          s.content[i].innerHTML = s.truncatedContentArr[i];
          var self = i;
          ReadMore.createLink(self);
        }
      }
      ReadMore.handleClick(s.content);
    },

    /**
     * Create Link
     * Creates and Inserts Read More Link
     * @param {number} index - index reference of looped item
     */
    createLink: function(index) {
      var readMoreLink = document.createElement('a');
      readMoreLink.setAttribute('id', `read-more_${index}`);
      readMoreLink.setAttribute('class', 'btn-more');
      readMoreLink.textContent = `${s.moreLink}`;

      s.content[index].appendChild(readMoreLink, s.content[index]);
    },

    /**
     * Handle Click
     * Toggle Click eve
     */
    handleClick: function(el) {
      var readMoreLink = document.querySelectorAll('.btn-more');

      for (var j = 0, l = readMoreLink.length; j < l; j++) {
        readMoreLink[j].addEventListener('click', function() {
          var moreLinkID = this.getAttribute('id');
          var index = moreLinkID.split('_')[1];

          el[index].classList.toggle('is-expanded');

          if (this.dataset.clicked !== 'true') {
            el[index].innerHTML = s.originalContentArr[index]; // Does not include created link
            this.textContent = s.lessLink;
            this.dataset.clicked = true;
            
            console.log(this.textContent);
          } else {
            el[index].innerHTML = s.truncatedContentArr[index];
            this.textContent = s.moreLink;
            this.dataset.clicked = false;
          }
          
          el[index].append(this); // Re-appended link here
          console.log(this);
        });
      }
    },

    /**
     * Open All
     * Method to expand all instances on the page.
     */
    openAll: function() {
      el = document.querySelectorAll('.btn-more');
      for (var i = 0; i < el.length; i++) {
        content[i].innerHTML = s.truncatedContentArr[i];
        el[i].innerHTML = s.moreLink;
      }
    },
  };
})();

ReadMore.init();
<main id="about">
  <div class="article js-read-more" data-rm-words="10">
    <h2>What are "Goals"?</h2>
    <p>Autem neque consequuntur sunt accusantium itaque at eum sed consectetur corporis culpa odit ratione, quam commodi provident quae, placeat voluptatum, debitis aspernatur nisi quibusdam?</p>
    <p>Autem neque consequuntur sunt accusantium itaque at eum sed consectetur corporis culpa odit ratione, quam commodi provident quae, placeat voluptatum, debitis aspernatur nisi quibusdam?</p>
  </div>

  <div class="article js-read-more" data-rm-words="10">
    <h2>Influences</h2>
    <p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Aspernatur, nesciunt tempore voluptates, deserunt ab earum magnam asperiores mollitia repellat praesentium optio cum ex cupiditate quasi quas? Autem neque consequuntur sunt accusantium itaque
      at eum sed consectetur corporis culpa odit ratione, quam commodi provident quae, placeat voluptatum, debitis aspernatur nisi quibusdam?</p>
    <p>Autem neque consequuntur sunt accusantium itaque at eum sed consectetur corporis culpa odit ratione, quam commodi provident quae, placeat voluptatum, debitis aspernatur nisi quibusdam?</p>
  </div>
</main>