多个多读/少读部分在页面上不起作用

Multiple read more / read less sections are not working on a page

我有多个页面的多读/少读部分。如果我在页面上使用一个多读/少读部分,那工作正常,如果我在页面上使用多个部分,那么只有一个部分有效,其他部分无效。我需要多个部分才能在同一页面上工作。

const content = document.querySelector(".content-inner");
const contentFull = document.querySelector(".content-full");
const more = document.querySelector(".read-more");
let open = false;

if (more) {
  more.addEventListener("click", (e) => {
    if (open) {
      content.removeAttribute("style");
      e.target.innerText = "click here";
      open = false;
    } else {
      content.style.maxHeight = `${contentFull.clientHeight}px`;
      e.target.innerText = "read less";
      open = true;
    }
  });
}
.read-more {
  display: inline-block;
  margin-top: 10px;
  font-weight: 400;
  cursor: pointer;
  font-size: 14px;
}
<div class="content">
  <div class="content-inner update-modal">
    <div class="content-full">
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
    </div>
  </div>
  <span class="read-more">click here</span>
</div>

您需要 select 相对 selection 来执行此操作,因为 class 是重复的。这里 toggleReadMore 函数 将附加到每个 read more class 并对内容内部 class.

执行高度操作操作

var prevOpened = null;
function toggleReadMore(e) {
  if(prevOpened !== null && e.target !== prevOpened){
     prevOpened.click();
  }
  // get the current section parent. This will make the selection on other class items easier. 
  var contentSection = e.target.closest('.content');
  var contentInner = contentSection.querySelector('.content-inner');

  if (e.target.textContent === "read less") {
    contentInner.removeAttribute("style");
    e.target.innerText = "click here";
    prevClicked = null;
    return;
  }
  contentInner.style.maxHeight = `${contentSection.querySelector('.content-full').clientHeight}px`;
  e.target.innerText = "read less";
  prevOpened = e.target;
}

var readMoreSections = document.querySelectorAll(".read-more");
readMoreSections.forEach(function(sections) {
  sections.addEventListener("click", toggleReadMore);
})
.read-more {
  display: inline-block;
  margin-top: 10px;
  font-weight: 400;
  cursor: pointer;
  font-size: 14px;
}

.content-inner {
  max-height: 20px;
  overflow: hidden;
}
<div class="content">
  <div class="content-inner update-modal">
    <div class="content-full">
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
    </div>
  </div>
  <span class="read-more">click here</span>
</div>


<div class="content">
  <div class="content-inner update-modal">
    <div class="content-full">
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
    </div>
  </div>
  <span class="read-more">click here</span>
</div>

编辑:已更新为仅打开最近点击的项目。

这是一项与事件委托有关的任务。单击事件(与大多数事件一样)从单击的元素冒泡到 document,您可以在上升过程中检测到事件。

下面的示例向您展示了如何使用事件委托。该代码是可重用的,它可以用在几乎任何元素结构的任何页面上,您还可以保留元素的 classes 和样式。此代码段也可用于动态页面,如果您添加或删除可扩展元素,它无需对 JS 进行任何更改即可工作 to/from 容器。

function toggleContent (options) {
  const {container, expandable, triggerer, autoClose} = options,
    contents = document.querySelectorAll(container),
    buttonText = ['Read more', 'Read less'];
  let current = null; // Keeps book of the currently open expandee

  function toggle (e) {
    const button = e.target;
    if (!button.matches(triggerer)) {return;} // Quit, an irrelevant element clicked 
    const commonParent = button.closest(expandable);
    if (!commonParent) {return;} // Quit, the expandable element was not found
    if (autoClose && current && button !== current) {
      // If autoClose is on, closes the current expandee
      toggle({target: current});
    }
    const state = +commonParent.classList.toggle('expanded');
    button.textContent = buttonText[state];
    current = state ? button : null;
  }

  // Add click listeners to all elements containing expandables
  contents.forEach(cont => cont.addEventListener('click', toggle));
}

// Activate ContentToggler
toggleContent({
  container: '.expandables-container', // Selector for the elements containing expandable elements
  expandable: '.expandable',   // Selector for expandable elements
  triggerer: '.toggle-button', // Selector for the element triggering expansion
  autoClose: true              // Indicates whether the expanded element is closed when a new element is expanded (optional)
});
.expandable {
  border: 1px solid #000;
  margin-bottom: 1em;
}

/* Hides all the expandees */
.expandable .expandee {
  display: none;
}

/* Shows the expandee when .expanded is added to the parent of expandee */
.expanded .expandee {
  display: block;
}
<div class="expandables-container">
  <div class="expandable">
    <p>Always visible content.</p>
    <div class="expandee">
      <p>More content.</p>
    </div>
    <button class="toggle-button">Read more</button>
  </div>
  <div class="expandable">
    <p>Toggle button can be placed above the expandee element.</p>
    <button class="toggle-button">Read more</button>
    <div class="expandee">
      <p>More content.</p>
    </div>
  </div>

  <p>Elements can be placed between expandables.</p>

  <div class="expandable">
    <p>Always visible content.</p>
    <div class="expandee">
      <p>More content.</p>
    </div>
    <p>Elements can be placed between expandable and toggle button.</p>
    <button class="toggle-button">Read more</button>
  </div>
  <div class="expandable">
    <p>The only requirement is, that the toggle button and expandee are descendants of expandable.</p>
    <div class="expandee">
      <p>And the button must not be placed inside expandee.</p>
    </div>
    <button class="toggle-button">Read more</button>
  </div>
</div>

想法是,所有可扩展项都包含在一个元素中。单击侦听器附加到该包装器,每个包装器只需要一个单击侦听器。这称为事件委托,它允许您随时自由地添加或删除内容 to/from 包装器,根本不需要更新脚本。

出于三个原因,所有内容都包含在 toggleContent 函数中。首先,它封装了代码,不需要引入全局变量。其次,它可以多次调用具有不同参数的函数,并在同一页面上创建不同类型的切换器。第三,将紧凑的代码包复制到另一个页面要容易得多。

toggle函数从事件对象中获取被点击的元素(e是自动从事件队列中传递过来的),如果元素与传入的触发选择器不匹配,则事件为取消。然后它找到触发器和要显示的元素(“expandee”)的公共父级,找到后,将 expanded class 添加到父级。

CSS 将使用后代组合符 .expanded .expandee 显示扩展项,当父元素具有 expanded class 时,它指的是扩展项元素。当前打开的 expandee 只需通过以当前元素作为目标的虚拟事件对象调用相同的函数即可关闭。最后更新触发器的文本值和当前活动元素。

值得注意的是,该示例是一个非常通用的 class 切换器,它仅更改 class 所单击元素的父级名称,您可以自由地在其中进行任何样式设置CSS 规则,它不一定是 display,也可以使用 height,或任何东西。

“小部件”通过调用 toggleContent 函数激活。包装器、可扩展元素和切换按钮的选择器在对象中传递。第四个参数控制自动关闭。如果你只想保持单个扩展元素可见,传递 true,当传递 false 或省略 属性 时,切换按钮将相互独立工作。

如果您需要对可切换内容进行更多控制,我建议您使用基于 OOP 的方法。 This OOP example 将此答案示例中的代码包装在 class 中,并提供一些用例来展示如何控制内容。当您了解 OOP 的工作原理时(或者您已经知道),您可以轻松地将方法添加到 class,例如。对于 hiding/showing 所有内容等