【问题标题】:Expanding all details tags展开所有详细信息标签
【发布时间】:2017-08-17 22:18:34
【问题描述】:

有人知道是否有办法为使用语义<details> 标记的页面创建展开所有链接?我设法创建了一个可以自动打开已关闭详细信息的链接:Link to details section that expands details section as well

现在我正在尝试添加一个链接来扩展所有<details>

我猜你可以用 javascript 做到这一点,但我在那里很弱。单击一个链接的效果会启动一个脚本,该脚本会在 html 中找到所有“

目前为止

<button onclick="openAll()">Expand All</button>

<script>function openAll() {
    var x = document.getElementsByTagName("details");
    var i;
    for (i = 0; i < x.length; i++) {
         x[i].setAttribute("open", "true");
}
</script>

以下内容适用于第一个 &lt;details&gt; 标签,但我猜我上面的循环不正确...

<script>
function openAll() {
    document.getElementsByTagName("details")[0].setAttribute("open", "true"); 
}
</script>

下面是我正在测试的虚拟 html

<details>Hello World<summary>summary</summary>lost</details>
<details>another<summary>good night moon</summary>find me</details>

【问题讨论】:

  • 您的代码对我来说似乎可以正常工作:jsfiddle.net/p7sr00ph 还是我错过了这个问题?当我单击按钮时,&lt;details&gt; 都会打开。
  • 你试过非沙盒环境吗?
  • 你的 openAll 函数不起作用,因为你错过了一个右括号。顺便说一句,x[i].open=true;做出同样的结果。

标签: javascript loops expand


【解决方案1】:

更新

OP 要求排除前 6 个 &lt;detail&gt;s。将.forEach() 方法换成了for 循环。

见片段 2


使用&lt;details&gt;.open 属性。打开为真,关闭为假。 片段中评论了详细信息。

片段 1

// Reference the toggle link
var xa = document.getElementById('expAll');

// Register link on click event
xa.addEventListener('click', function(e) {

  /* Toggle the two classes that represent "state"
  || determined when link is clicked
  */
  e.target.classList.toggle('exp');
  e.target.classList.toggle('col');

  // Collect all <details> into a NodeList
  var details = document.querySelectorAll('details');

  /* Convert NodeList into an array then iterate
  || throught it...
  */
  Array.from(details).forEach(function(obj, idx) {

    /* If the link has the class .exp...
    || make each <detail>'s open attribute true
    */
    if (e.target.classList.contains('exp')) {
      obj.open = true;
      // Otherwise make it false
    } else {
      obj.open = false;
    }

  });

}, false);
<a href='#/' id='expAll' class='exp'>Expand All</a>

<details>Hello World
  <summary>summary</summary>lost</details>
<details>another
  <summary>good night moon</summary>find me</details>

片段 2

// Reference the toggle link
var xa = document.getElementById('expAll');

// Register link on click event
xa.addEventListener('click', function(e) {

  /* Toggle the two classes that represent "state"
  || determined when link is clicked
  */
  e.target.classList.toggle('exp');
  e.target.classList.toggle('col');

  // Collect all <details> into a NodeList
  var details = document.querySelectorAll('details');

  /* Convert NodeList into an array then iterate
  || throught it...
  */
  var D = Array.from(details);

  /* Start a for loop at 6 instead of 0
  || Now 0 - 5 details are excluded
  */
  for (let i = 6; i < D.length; i++) {

    /* If the link has the class .exp...
    || make each <detail>'s open attribute true
    */
    if (e.target.classList.contains('exp')) {
      D[i].open = true;
      // Otherwise make it false
    } else {
      D[i].open = false;
    }

  }

}, false);
<a href='#/' id='expAll' class='exp'>Expand All</a>

<details>Hello World
  <summary>summary 0</summary>lost</details>
<details>another
  <summary>good night moon 1</summary>find me</details>
<details>Hello World
  <summary>summary 2</summary>lost</details>
<details>another
  <summary>good night moon 3</summary>find me</details>
<details>Hello World
  <summary>summary 4</summary>lost</details>
<details>another
  <summary>good night moon 5</summary>find me</details>
<details>Hello World
  <summary>summary 6</summary>lost</details>
<details>another
  <summary>good night moon</summary>find me</details>
<details>Hello World
  <summary>summary</summary>lost</details>
<details>another
  <summary>good night moon</summary>find me</details>
<details>Hello World
  <summary>summary</summary>lost</details>
<details>another
  <summary>good night moon</summary>find me</details>
<details>Hello World
  <summary>summary</summary>lost</details>
<details>another
  <summary>good night moon</summary>find me</details>
<details>Hello World
  <summary>summary</summary>lost</details>
<details>another
  <summary>good night moon</summary>find me</details>
<details>Hello World
  <summary>summary</summary>lost</details>
<details>another
  <summary>good night moon</summary>find me</details>
<details>Hello World
  <summary>summary</summary>lost</details>
<details>another
  <summary>good night moon</summary>find me</details>
<details>Hello World
  <summary>summary</summary>lost</details>
<details>another
  <summary>good night moon</summary>find me</details>
<details>Hello World
  <summary>summary</summary>lost</details>
<details>another
  <summary>good night moon</summary>find me</details>

【讨论】:

  • 有没有办法编辑你的代码,让它从元素 [6] 开始?即展开除 [0]-[5] 位置之外的所有细节。
  • 是的,它创建了一个详细信息数组,因此您在 forEach() 块中放置了另一个条件。待机。
  • 请注意,如果锚按钮有任何子元素,它们可以最终成为点击事件的目标。要么给子元素pointer-events: none 样式,要么确保在类切换/检查代码中直接引用锚元素。
  • (续)使用true 而不是false 作为addEventListener 中的最后一个参数也可以解决这个问题。
【解决方案2】:

解决方案对我不起作用。所以,我改变了@testing123 解决方案,让它与一个完整的例子一起工作。

function openAll() {
  var elems = document.getElementsByTagName("details");
  document.getElementById("btnExpandHideAllDetails").innerHTML = "Hide All Details on page";
  document.getElementById("btnExpandHideAllDetails").setAttribute( "onClick", "javascript: closeAll();");

  for (var i = 4; i <= elems.length; i++){
    elems[i].setAttribute("open", "true");
    }
}

function closeAll() {	
  var elems = document.getElementsByTagName("details");
  document.getElementById("btnExpandHideAllDetails").setAttribute( "onClick", "javascript: openAll();" );
  document.getElementById("btnExpandHideAllDetails").innerHTML = "Expand All Details on Page";	
  
  for (var i = 4; i <= elems.length; i++){
    elems[i].removeAttribute("open");
  }
}
<button id="btnExpandHideAllDetails" onclick="openAll()" style="color:white;background-color:green;">Expand All Details on Page</button>
    
    
<details>
  <summary>0</summary>                            
</details>
<details>
  <summary>1</summary>                            
</details>
<details>
  <summary>2</summary>                            
</details>
<details>
  <summary>3</summary>                            
</details>
<details>
  <summary>Expand me.</summary>                        
    Hello World!
</details>

【讨论】:

    【解决方案3】:

    从 JavaScript 切换页面中的所有 details 元素:

    document.body.querySelectorAll('details').forEach((e) => (e.hasAttribute('open')) ? e.removeAttribute('open') : e.setAttribute('open',true))
    

    关闭所有其他details,当一个打开时:

    document.body.querySelectorAll('summary').forEach((e) => e.addEventListener("click", (e) => {
       document.body.querySelectorAll('details').forEach((e) => (e.hasAttribute('open')) ? e.removeAttribute('open') : '')
    }))
    <details>
        <summary>Details</summary>
        Something small enough to escape casual notice.
    </details>
    
    <details>
        <summary>Details</summary>
        Something small enough to escape casual notice.
    </details>
    
    <details>
        <summary>Details</summary>
        Something small enough to escape casual notice.
    </details>

    当一个details 处于打开状态时,一次全部切换:

    document.body.querySelectorAll('summary').forEach((e) => e.addEventListener("click", (e) => {
       e.preventDefault()
       document.body.querySelectorAll('details').forEach((e) => (e.hasAttribute('open')) ? e.removeAttribute('open') : e.setAttribute('open', true))
    }))
    <details>
        <summary>Details</summary>
        Something small enough to escape casual notice.
    </details>
    
    <details>
        <summary>Details</summary>
        Something small enough to escape casual notice.
    </details>
    
    <details>
        <summary>Details</summary>
        Something small enough to escape casual notice.
    </details>

    【讨论】:

      【解决方案4】:

      这是我的解决方案:

          const expandElements = shouldExpand => {
              let detailsElements = document.querySelectorAll("details");
              
              detailsElements = [...detailsElements];
      
              if (shouldExpand) {
                  detailsElements.map(item => item.setAttribute("open", shouldExpand));
              } else {
                  detailsElements.map(item => item.removeAttribute("open"));
              }
          };
      

      这里是如何使用它的:

      <button onClick="expandElements(true)">Expand</button>
      <button onClick="expandElements(false)">Collapse</button>
      

      【讨论】:

        【解决方案5】:

        所以 zer00ne 的解决方案似乎有时可以在浏览器(Chrome / Firefox)中运行。有时在第二次单击时它会起作用。有时在第一个。有时根本没有。可能是因为details标签还没有被完全支持?

        我采用了下面的解决方案......只是在 31 处有一个绝对端点,而不是在结尾处停止。

        <button id="expand" onclick="openAll()">Expand All +</button>
        
        var elems = document.getElementsByTagName("details");
        
        function openAll() {
          for (var i = 4; i <= 31; i++){
            elems[i].setAttribute("open", "true");
          }
          document.getElementById("expand").setAttribute( "onClick", "javascript: closeAll();" );
          document.getElementById("expand").innerHTML = "Collapse All -";
        }
        
        function closeAll() {
          for (var i = 4; i <= 31; i++){
            elems[i].removeAttribute("open");
          }
          document.getElementById("expand").setAttribute( "onClick", "javascript: openAll();" );
          document.getElementById("expand").innerHTML = "Expand All +";
        }
        

        【讨论】:

        • 我的解决方案使用 Chrome 和 Firefox PC 似乎可以正常运行。片段 2 是 OP 请求的行为,其中前 6 个细节被跳过。你知道如何重现这个问题,还是因为它太随意而无法确定?
        【解决方案6】:

        我想要一些我自己使用的东西,所以我不在乎它是否适用于所有浏览器。

        我的方法是在包含详细信息元素的页面每个部分的每个标题中创建展开/关闭按钮。作为内联块的按钮位于每个部分标题的末尾,无需我手动添加它们。

        代码遍历页面详细信息元素以找到最接近的父级,即部分、旁白、文章、主要或 div。然后使用这些父分组元素的唯一数组将按钮添加到它们各自的标题。这些标题是否为 h1 - h6 无关紧要,无论每个部分中的第一个标题是什么,都会使用“展开”按钮修改标题。

        按钮本身会更新以在“展开”时显示“关闭”,反之亦然,因此其行为类似于切换。

        因为我希望能够搜索页面上的内容,所以我还在主元素的第一个标题之后添加了一个“全部展开”按钮。这说明您需要“全部展开”才能在页面中搜索。

        此“全部展开”会更新每个部分中的子“展开”按钮以显示“关闭”。它还会切换到“全部关闭”。

        在我看来,只有当您处理使用语义元素并且页面上有大量内容的结构化内容时,才需要这种方法。

        details 元素的一个失败之处在于它确实隐藏了页面搜索中的内容,这是我为解决可能被搜索的内容所做的最大努力,例如您可能想要隐藏代码 sn 的技术说明-ps 和设置软件的冗长说明,但仍想搜索给定的关键字。

        document.addEventListener("DOMContentLoaded", function (t) {
        var groups = ["section", "aside", "article", "main", "div"], headings = ["h1", "h2", "h3", "h4", "h5", "h6"],
            parents = [],
            details = document.querySelectorAll("details");
        for (var detail of details) for (var group of groups) {
            var parent = detail.closest(group);
            if (parent) {
                if (!parents.includes(parent)) for (var heading in parents.push(parent), headings) {
                    var location = parent.getElementsByTagName(headings[heading]);
                    if (location.length) {
                        var button = document.createElement("button");
                        button.classList.add("details-helper"),
                            button.setAttribute("type", "button"),
                            button.textContent = "Expand",
                            button.style.display = "inline-block",
                            location[0].appendChild(button),
                            button.addEventListener("click", expandGroup(parent));
                    }
                }
                break;
            }
        }
        
        if (parents.length) {
            var nav = document.createElement("nav");
            nav.classList.add("text-search");
            var button = document.createElement("button");
            button.classList.add("search-helper"),
                button.setAttribute("type", "button"),
                button.textContent = "Expand All",
                button.style.display = "inline-block",
                nav.appendChild(button),
                button.addEventListener("click", expandAll());
            var p = document.createElement("p");
            p.style.display = "inline-block";
        
            var em = document.createElement("em");
            em.textContent = "Press before searching this page with CTRL+F";
            p.appendChild(em);
            nav.appendChild(p);
            for (heading of headings) {
                if (location = document.querySelector("main " + heading)) {
                    location.parentNode.insertBefore(nav, location.nextSibling);
                    break;
                }
            }
        }
        
        function expandGroup(group) {
            return function () {
                this.classList.contains("close-details") ? (this.classList.remove("close-details"), this.textContent = "Expand", state = false) : (this.classList.add("close-details"), this.textContent = "Close", state = true);
                var details = group.getElementsByTagName("details");
                Array.from(details).forEach(function (detail) {
                    detail.open = state;
                })
            }
        }
        
        function expandAll() {
            return function () {
                this.classList.contains("close-all-details") ? (this.classList.remove("close-all-details"), this.textContent = "Expand All", state = false) : (this.classList.add("close-all-details"), this.textContent = "Close All", state = true);
                var buttons = document.querySelectorAll('.details-helper');
                Array.from(buttons).forEach(function (button) {
                    if(!state) {
                        button.classList.remove("close-details");
                    } else {
                        button.classList.add("close-details");
        
                    }
                    button.textContent = state ? "Close" : "Expand";
                    for (var group of groups) {
                        var parent = button.closest(group);
                        if (parent) {
                            var details = parent.querySelectorAll("details");
                            Array.from(details).forEach(function (detail) {
                                detail.open = state;
                            })
                        }
                    }
                })
            }
        }
        });
        

        这可以包含在带有脚本标签的文档中 - 'details-helper.js' - 并且创建的按钮包括样式。

        使按钮与细节元素的默认样式保持一致:

        .search-helper,
        .details-helper {
            font-size: .66em;
            margin: 0 1em;
            outline: none;
            padding: 0.25em;
            text-transform: uppercase;
            vertical-align: text-bottom;
            width: 8em;
        }
        .search-helper {
            width: 10em;
        }
        .search-helper::after,
        .details-helper::after {
            content: ' ▶';
        }
        .close-all-details::after,
        .close-details::after {
            content: ' ▼';
        }
        

        您的里程可能会因此解决方案而异,但希望您会发现其中的一些有用。假设您的页面具有内容的主要和逻辑结构。这还没有在每个元素都嵌套在许多 div 中并且没有文章或部分的页面上进行测试。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-12-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多