Изменить отображение элемента списка, его дочернего элемента и переместить элемент вверх по списку

#javascript #html #css

#javascript #HTML #css

Вопрос:

У меня есть список с элементами списка, стилизованными под встроенный блок. При нажатии на каждый элемент списка я хочу:

  1. изменить отображение:inline-block; на отображение:block; элемента списка,
  2. изменить отображение: нет; на отображение: блок; дочернего div
  3. Переместите выбранный элемент в начало списка
  4. Если щелкнуть более одного элемента, все они делают то же самое и перемещаются вверх по списку вместе.

При повторном нажатии (переключении) я хочу, чтобы список изменил вышеуказанное (изменил отображение и вернулся в исходное положение).

До сих пор мне удалось только изменить отображение элемента списка на block, но я не могу настроить таргетинг на дочерний div с помощью element.children или переместить элемент списка наверх.

 function showCombo(ID) {
  var x = document.getElementById(ID);
  var xshow = getComputedStyle(x, null).display; //

  if (xshow == "inline-block") {
    x.style.display = "block";
  } else {
    x.style.display = "inline-block";
  }
} 
 li {
  display: inline-block;
  border: 1px solid black;
  border-radius: 3px;
  cursor: pointer;
}

li div {
  display: none;
} 
 <ul>
  <li ID="1" onclick="showCombo(1)">
    <p>Title 1</p>
    <div>Show content</div>
  </li>
  <li ID="2" onclick="showCombo(2)">
    <p>Title 2</p>
    <div>Show content</div>
  </li>
  <li ID="3" onclick="showCombo(3)">
    <p>Title 3</p>
    <div>Show content</div>
  </li>
  <li ID="4" onclick="showCombo(4)">
    <p>Title 4</p>
    <div>Show content</div>
  </li>
  <li ID="5" onclick="showCombo(5)">
    <p>Title 5</p>
    <div>Show content</div>
  </li>
</ul> 

Ответ №1:

Переключите класс со всеми свойствами, и это было бы проще:

 function showCombo(x) {
  x.classList.toggle('active')
} 
 li {
  border: 1px solid black;
  margin:2px;
  border-radius: 3px;
  cursor: pointer;
}

li div {
  display: none;
}

ul {
  display:flex;
  flex-wrap:wrap;
  list-style:none;
}
li.active {
   width:100%; /* full width*/
   order:-1; /* move to the top */
}
li.active div {
  display:block; /* show div */
} 
 <ul>
  <li onclick="showCombo(this)">
    <p>Title 1</p>
    <div>Show content</div>
  </li>
  <li onclick="showCombo(this)">
    <p>Title 2</p>
    <div>Show content</div>
  </li>
  <li  onclick="showCombo(this)">
    <p>Title 3</p>
    <div>Show content</div>
  </li>
  <li  onclick="showCombo(this)">
    <p>Title 4</p>
    <div>Show content</div>
  </li>
  <li onclick="showCombo(this)">
    <p>Title 5</p>
    <div>Show content</div>
  </li>
</ul> 

Комментарии:

1. Спасибо! Это впечатляюще просто. Усложнит ли ситуацию, если первый элемент списка откроется в своем собственном месте, не перемещаясь наверх, но если щелкнуть два или более, они оба переместятся наверх?

2. @suverenia да, это сделало бы сценарий немного сложным. Возможно, мне потребуется добавить больше JS для обработки этого

3. Хорошо, я все равно доволен этим! Можно ли легко закрыть и открыть все?

4. @suverenia да, вы можете переместить active класс в ul и переключить его там и немного изменить CSS, чтобы настроить его как ul.active li

5. Хорошо, спасибо. Однако это вызывает у меня проблемы, поскольку дочерний div содержит ссылки, изображения и поля ввода, которые нельзя использовать.

Ответ №2:

Я создал вашу идею, используя javascript с большим упором на нее, но вы можете использовать order в css, как в предыдущем ответе, это будет проще, если у вас есть вопрос, задайте мне, и если вы хотите немного отредактировать, скажите мне, я добавлю ссылки на объяснения некоторых событий, функций, которые я использовалих в моем коде javascript на случай, если вы их не знаете

insertBefore

добавить

classlist

getElementsByClassName

getAttribute

setAttribute

 var li = document.getElementsByClassName("li"),
    ul = document.getElementById("ul");

for (let i = 0; i < li.length; i = i   1) {
  
  li[i].setAttribute("index", i); // Create attribute named index and its value will be the i, this is to know the index of the li, we need it when clicked on it again
  
  li[i].setAttribute("firstclick", "yes"); // This is to know if we clicked at it firsttime or secondtime toggle
  
  li[i].onclick = function () {
   
    if (this.getAttribute("firstclick") == "yes") {
      this.setAttribute("firstclick", "no"); // Change it to no to when clicking it once again read the second case
      
       ul.prepend(this); // Put the clicked li at the top of the li, prepend means to put it the first element
      this.classList.add("displayBlock") // add the class displayBlock check it in the css it contains display: block
            this.getElementsByClassName("content")[0].classList.add("displayBlock"); // Add the displayBlock to the div inside the clicked li to show
    } else {
      this.setAttribute("firstclick", "yes"); // Change it to yes to when clicking it once again read the first case
      
      ul.insertBefore(this, li[parseInt(this.getAttribute("index"))   1]) // Insert It to its original position
      
     this.classList.remove("displayBlock"); // Remove the display block class
      this.getElementsByClassName("content")[0].classList.remove("displayBlock"); // Remove the display block class
      
      
    }
    
    
  }
} 
 li {
  display: inline-block;
  border: 1px solid black;
  border-radius: 3px;
  cursor: pointer;
}

li div {
  display: none;
}

.displayBlock {
  display: block;
} 
 <ul id="ul">
 <li class="li" >
    <p>Title 1</p>
    <div class="content">Show content</div>
  </li>
  <li class="li" >
      <p>Title 2</p>
      <div class="content">Show content</div>
  </li>
  <li class="li" >
      <p>Title 3</p>
      <div class="content">Show content</div>
  </li>
  <li class="li" >
      <p>Title 4</p>
      <div class="content">Show content</div>
  </li>
  <li class="li" >
      <p>Title 5</p>
      <div class="content">Show content</div>
  </li>
</ul> 

Комментарии:

1. Привет, Таха. Спасибо. У вашего скрипта есть несколько проблем. 1) если вы развернете все, у вас будет неустойчивое поведение, связанное с полем между элементами, а также с их положением и порядком. 2) В некоторых случаях некоторые элементы списка не перемещаются вверх, а элементы списка застревают сверху и снизу. 3) div не может содержать поле ввода div.

2. Здравствуйте, для пункта 1 вы можете редактировать css, например, добавлять поля, и сейчас это не наша задача, для других пунктов да, вы правы, я могу это решить, но просто используйте порядок в css, как в предыдущем ответе, и это будет лучше и проще, потому что я напишу много новыхстроки в javascript (код будет больше :)). Самое главное, что ваша идея решена, и я пытаюсь ее решить. Хорошего дня :), если у вас есть какие-либо вопросы, просто спросите