【问题标题】:Using javascript to target a parent with css使用 javascript 来定位具有 css 的父级
【发布时间】:2021-06-10 19:21:52
【问题描述】:

我还是个新手,还在学习,但我正在努力完成一个个人项目,所以我在这里寻找一个优雅的解决方案。 把这个项目想象成一个“待办事项”列表。我有多个带有复选框的列表,当复选框为:checked 时,我需要它来更改父li 容器的background-color

而且,在页面顶部,我有一个复选框来隐藏所有已完成的任务,这是带有已完成 (:checked) 子项的 li 容器。 根据我的阅读,这不可能完全使用 CSS,因为您无法选择样式的父级。然而,我对 JavaScript 的了解太有限,无法理解如何自己制定解决方案或重新利用我在这里看到的许多类似问题的解决方案。我找不到可以将样式传递给display: none; 作为切换的样式。

为了简单起见,我正在寻找一个纯 JS(无 jQuery)的解决方案。

“隐藏已完成任务”复选框应使用display: none / display: flow; 打开或关闭所有已完成任务,单个任务复选框应仅更改父级li 背景颜色。

/*this rule hides all task. I want to only hide the task which are :checked*/

#hide-toggle1:checked~* .task1 {
  display: none;
}


/*this css rule hides only the checked input. I need it to hide the whole <li>*/

#hide-toggle2:checked~* .task2>input:checked {
  display: none;
}
<body>
  <input type="checkbox" id="hide-toggle1">
  <label for="hide-toggle1">Hide completed tasks</label>
  <ul>
    <li class="task1">
      <input type="checkbox" id="1-1" value="0">
      <label for="1-1">Task 1</label>
    </li>
    <li class="task1">
      <input type="checkbox" id="1-2" value="0">
      <label for="1-2">Task 2</label>
    </li>
    <li class="task1">
      <input type="checkbox" id="1-3" value="0">
      <label for="1-3">Task 3</label>
    </li>
  </ul>

  <input type="checkbox" id="hide-toggle2">
  <label for="hide-toggle2">Hide completed tasks</label>
  <ul>
    <li class="task2">
      <input type="checkbox" id="2-1" value="0">
      <label for="2-1">Task 1</label>
    </li>
    <li class="task2">
      <input type="checkbox" id="2-2" value="0">
      <label for="2-2">Task 2</label>
    </li>
    <li class="task2">
      <input type="checkbox" id="2-3" value="0">
      <label for="2-3">Task 3</label>
    </li>
  </ul>
</body>

【问题讨论】:

  • CSS 没有办法回溯元素树。您不能根据其子元素来定位元素。

标签: javascript html css-selectors


【解决方案1】:

我强烈推荐学习一些javascript,它会让你的生活更轻松。我以最基本的形式编写了这段代码,试图帮助你更好地理解它。我也试图评论我在做什么。我为列表中的每个输入添加了一个'check-input' 类,并为隐藏按钮添加了一个'hide-list' 类。

// Add an event to each 'input' tag
function AddEventListeners() {
  // get all items marked with a class 'check-input'
  let inputs = document.getElementsByClassName('check-input');
  // whatever background color you want the 'li' to turn once checked
  let desiredBackgroundColor = "green";
  // loop through all input elements
  for (let i = 0; i < inputs.length; i++) {
    // add the event listener for a 'click'
    inputs[i].addEventListener('click', function() {
      // get the parent element which would be the 'li'
      let li_parent = this.parentElement;
      // set its background color to transparent if it has already been clicked
      if (li_parent.style.backgroundColor == desiredBackgroundColor) {
        li_parent.style.backgroundColor = "transparent";
      } else {
        if (this.checked == true) {
          li_parent.style.backgroundColor = desiredBackgroundColor;
        } else {
          li_parent.style.backgroundColor = "transparent";
        }
      }
    });
  }

  // get all buttons marked by a class 'hide-list'
  let hideButtons = document.getElementsByClassName('hide-list');
  // add a pressed state variable to see when the button has been pressed
  let pressed = false;
  // loop through all hide buttons
  for (let i = 0; i < hideButtons.length; i++) {
    // add the event listener
    hideButtons[i].addEventListener('click', function() {
      // get the 'li' marked with 'task' and their number, either 1 or 2
      let children_li = document.getElementsByClassName('task' + (i + 1));

      // check if the button has already been pressed
      if (pressed == true) {
        for (let j = 0; j < children_li.length; j++) {
          // if it has, make the elements visible again
          children_li[j].style.display = "block";
        }
        pressed = false;
        return;
      }
      pressed = true;
      for (let j = 0; j < children_li.length; j++) {
        // if the elements have been marked by the background color, make them invisible
        if (children_li[j].style.backgroundColor == desiredBackgroundColor) {
          children_li[j].style.display = "none";
        } else {
          children_li[j].style.display = "block";
        }
      }
    });
  }
}
<body onload="AddEventListeners();">
  <input type="checkbox" id="hide-toggle1" class="hide-list">
  <label for="hide-toggle1">Hide completed tasks</label>
  <ul>
    <li class="task1">
      <input type="checkbox" id="1-1" value="0" class="check-input">
      <label for="1-1">Task 1</label>
    </li>
    <li class="task1">
      <input type="checkbox" id="1-2" value="0" class="check-input">
      <label for="1-2">Task 2</label>
    </li>
    <li class="task1">
      <input type="checkbox" id="1-3" value="0" class="check-input">
      <label for="1-3">Task 3</label>
    </li>
  </ul>

  <input type="checkbox" id="hide-toggle2" class="hide-list">
  <label for="hide-toggle2">Hide completed tasks</label>
  <ul>
    <li class="task2">
      <input type="checkbox" id="2-1" value="0" class="check-input">
      <label for="2-1">Task 1</label>
    </li>
    <li class="task2">
      <input type="checkbox" id="2-2" value="0" class="check-input">
      <label for="2-2">Task 2</label>
    </li>
    <li class="task2">
      <input type="checkbox" id="2-3" value="0" class="check-input">
      <label for="2-3">Task 3</label>
    </li>
  </ul>
</body>

推荐一些好的免费 JS 教程

https://www.sololearn.com/learning

和/或

https://www.w3schools.com/js/default.asp

【讨论】:

【解决方案2】:

我建议使用通用类:隐藏复选框:hideall el 和您的列表项:task el 这样您就可以将事件addEventListener 添加到所有具有el 类的复选框中。

从那里您可以检查单击的项目是否具有 hidealltask 类。

如果它的task 和它的checked 添加绿色到它的父li 元素。

如果是hideall,抓住所有下一个ul's 选中li's 并隐藏...

document.querySelectorAll(".el").forEach(el => {
  el.addEventListener("click", function(event) {

    if (event.target.classList.contains('task') && event.target.checked) {
      event.target.parentElement.style.backgroundColor = "green";} else {
      event.target.parentElement.style.backgroundColor = ""}

    if (event.target.classList.contains('hideall')) {
      let e = event.target.nextElementSibling.nextElementSibling.querySelectorAll(".task:checked");
      
      event.target.checked ? e.forEach(li => {li.parentElement.style.display = "none"
      }) : e.forEach(li => {li.parentElement.style.display = "flow"; li.parentElement.classList.add("dot")})
    }
  });
})
/*this will bring missing dot afte show hide back*/

.dot::before {
    color: black;
    content: "•  ";
    margin-left: -13px;
    padding-right:4px;
}
<body>
  <input type="checkbox" id="hide-toggle1" class="hideall el">
  <label for="hide-toggle1">Hide completed tasks</label>
  <ul>
    <li class="task1">
      <input type="checkbox" id="1-1" value="0" class="task el">
      <label for="1-1">Task 1</label>
    </li>
    <li class="task1">
      <input type="checkbox" id="1-2" value="0" class="task el">
      <label for="1-2">Task 2</label>
    </li>
    <li class="task1">
      <input type="checkbox" id="1-3" value="0" class="task el">
      <label for="1-3">Task 3</label>
    </li>
  </ul>

  <input type="checkbox" id="hide-toggle2" class="hideall el">
  <label for="hide-toggle2">Hide completed tasks</label>
  <ul>
    <li class="task2">
      <input type="checkbox" id="2-1" value="0" class="task el">
      <label for="2-1">Task 1</label>
    </li>
    <li class="task2">
      <input type="checkbox" id="2-2" value="0" class="task el">
      <label for="2-2">Task 2</label>
    </li>
    <li class="task2">
      <input type="checkbox" id="2-3" value="0" class="task el">
      <label for="2-3">Task 3</label>
    </li>
  </ul>
</body>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-14
    • 2012-01-08
    • 2017-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多