html5 подробный тег открыть одну за другой JavaScript-функцию, работающую странно

Я использую тег HTML5 для раздела часто задаваемых вопросов о компании. Проблема заключалась в том, что если пользователь открыл другой вопрос, другой вопрос не будет закрыт автоматически. Поэтому я искал в Интернете и нашел следующее решение:

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");
        }
      }
    }

В некотором смысле этот код работает правильно, но у него есть небольшие проблемы. Иногда он открывает два вопроса одновременно и работает забавно. Есть ли способ, чтобы он мог работать правильно? Это должно работать на рабочем столе, планшете и мобильном телефоне.

НЕ НУЖНЫЙ ЭФФЕКТ:

Я создал скрипку http://jsfiddle.net/877tm/ со всем кодом. Javascript делает свою работу там, если вы хотите увидеть его вживую, нажмите здесь.

5 ответов

Так как вы пометили jQuery, вы можете просто сделать это:

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

Все это делает, это удалить open атрибут всего detail теги при нажатии на любой detail, а затем снова откройте тот, на который вы только что нажали.

http://jsfiddle.net/877tm/3/

  1. Функция дырки thisindex глупа и может быть удалена. Вы можете просто передать элемент details в closeAll.

  2. CloseAll довольно глупо, он также ищет детали в цикле for, вау.

// закрыть все

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");
        }
    }
}

В случае, если вы хотите написать чистый код.

  1. Вы должны использовать $.on или addEventlistener.
  2. Старайтесь быть в определенном контексте и манипулировать только деталями в этом контексте. (Что произойдет, если вы хотите иметь две области аккордеона. Или некоторые обычные детали на одном сайте, но не внутри группы.)
  3. Искать детали в группе, только если детали были открыты, а не закрыты.
  4. Придайте свойству boolen open некоторую любовь вместо использования атрибута content

Я сделал небольшую скрипку, которая пытается это сделать.

Чтобы сделать детали как тег аккордеона, вы можете использовать ниже 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);
  }

У меня возникла проблема с ответом @MattDiamant, когда Firefox удалял атрибут open, но не помещал атрибут open в выбранную деталь. Я внес небольшое изменение в его код, чтобы он ориентировался на идентификатор выбранного в данный момент элемента детали.

Теперь, когда я нажимаю на<details>элемент, затем щелкните другой, он сворачивает первый элемент и отображает второй.

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

У меня есть решение с помощью 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");
                }
            });
        }
    });
Другие вопросы по тегам