最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

html - html5 details tag open one by one javascript function working strange - Stack Overflow

programmeradmin0浏览0评论

I'm using the HTML5 tag details for a FAQ section of a pany. An issue was that if the user opened another question the other question would not close automatically. Therefore I searched on the web and found the following solution:

function thisindex(elm){
      var nodes = elm.parentNode.childNodes, node;
      var i = 0, count = i;
      while( (node=nodes.item(i++)) && node!=elm )
        if( node.nodeType==1 ) count++;
      return count;
    }

    function closeAll(index){
      var len = document.getElementsByTagName("details").length;

      for(var i=0; i<len; i++){
        if(i != index){
          document.getElementsByTagName("details")[i].removeAttribute("open");
        }
      }
    }

This code does work properly in some sense but it has some small issues. Sometimes it opens two questions at the same time and works funny. Is there a method so this can work properly? This should work on desktop, tablet and mobile.

NOT DESIRED EFFECT:

I created a fiddle / with all the code. The javascript is doing it's work there, ig you want to see it live click here.

I'm using the HTML5 tag details for a FAQ section of a pany. An issue was that if the user opened another question the other question would not close automatically. Therefore I searched on the web and found the following solution:

function thisindex(elm){
      var nodes = elm.parentNode.childNodes, node;
      var i = 0, count = i;
      while( (node=nodes.item(i++)) && node!=elm )
        if( node.nodeType==1 ) count++;
      return count;
    }

    function closeAll(index){
      var len = document.getElementsByTagName("details").length;

      for(var i=0; i<len; i++){
        if(i != index){
          document.getElementsByTagName("details")[i].removeAttribute("open");
        }
      }
    }

This code does work properly in some sense but it has some small issues. Sometimes it opens two questions at the same time and works funny. Is there a method so this can work properly? This should work on desktop, tablet and mobile.

NOT DESIRED EFFECT:

I created a fiddle http://jsfiddle/877tm/ with all the code. The javascript is doing it's work there, ig you want to see it live click here.

Share Improve this question edited Aug 20, 2021 at 9:22 Toto 91.5k63 gold badges95 silver badges132 bronze badges asked Nov 16, 2013 at 20:39 Daniel Ramirez-EscuderoDaniel Ramirez-Escudero 4,04713 gold badges46 silver badges81 bronze badges
Add a ment  | 

5 Answers 5

Reset to default 6

Since you tagged jQuery, you can just do this:

$('.info').on('click', 'details', function () {
    $('details').removeAttr('open');
    $(this).attr('open', '');
});

All this does is remove the open attribute of all detail tags when you click on any detail, and then reopen the one you just clicked on.

http://jsfiddle/877tm/3/

  1. the hole thisindex function is stupid and can be removed. You can simply pass the details element to closeAll.

  2. The closeAll is quite stupid, too it searches for details in the for loop, wow.

// closeAll

function closeAll (openDetails){
    var details = document.getElementsByTagName("details");
    var len = details.length;
    for(var i=0; i<len; i++){
        if(details[i] != openDetails){
            details[i].removeAttribute("open");
        }
    }
}

In case you want write clean code.

  1. You should use $.on or addEventlistener.
  2. Try to be in a specific context and only manipulate details in this context. (What happens, if you want to have two accordion areas. Or some normal details on the same site, but not inside of the group.)
  3. Only search for details in the group, if details was opened not closed.
  4. Give the boolen open property some love, instead of using the content attribute

I made small fiddle, which trys to do this.

To make details as accordion tag you can use below jquery.

$("#edit-container details summary").click(function(e) {
    var clicked = $(this).attr('aria-controls');
    closeAll(clicked);
});
function closeAll (openDetailid){
      $("#edit-container details" ).each(function( index ) {
        var detailid = $(this).attr('id');
        var detailobj = document.getElementById(detailid);
          if (openDetailid != detailid ) {
           detailobj.open = false;
          }
       });
      $('html, body').stop().animate({ scrollTop: $('#'+openDetailid).offset().top -100 }, 1000);
  }

I had an issue with the answer provided by @MattDiamant where Firefox was removing the open attribute but was not putting the open attribute on the selected detail. I made a small change to his code so it targeted the ID of the currently selected detail element.

Now when I click on a <details> element then click on another, it collapses the first element and displays the second.

$('details').click(function(e){
    $('details').removeAttr('open');
    $(e.currentTarget.id).attr('open', '');
});

I have a solution with jQuery

$('details').on('click', function(ev){ //on a '<details>' block click
        ev.preventDefault(); //prevent the default behavior
        var attr = $(this).attr('open');
        if (typeof attr !== typeof undefined && attr !== false){ //if '<details>' block is open then close it
            $(this).removeAttr('open');
        }else{ // if '<details>' block is closed then open the one that you clicked and close all others
            var $that = $(this); //save the clicked '<details>' block
            $(this).attr('open','open'); //open the '<details>' block
            $('details').each(function(){ //loop through all '<details>' blocks
                if ($that.is($(this))){ //check if this is the one that you clicked on, if it is than open it or else close it
                    $(this).attr('open','open');
                }else{
                    $(this).removeAttr("open");
                }
            });
        }
    });
发布评论

评论列表(0)

  1. 暂无评论