Using only JS and css, can I implement a filter, so that: clicking/tapping within a JS dropdown menu shows/hides page divs by data-type?

huangapple go评论96阅读模式
英文:

Using only JS and css, can I implement a filter, so that: clicking/tapping within a JS dropdown menu shows/hides page divs by data-type?

问题

通过SO会员the.marolie的帮助,我学会了如何实现JS过滤器/选择器[称为“演示JS过滤器”]。我已经在测试页面上完美地实现了这个功能:根据在HTML主体中为它们分配的“数据类型”,它可以显示/隐藏<div>元素。然而,选择是通过滑动下拉列表<select>并在首选选项上释放来进行的。这不是我想要的。

我想要利用现有的导航栏下拉菜单[“我的下拉菜单”]作为过滤器/选择器。我特别想保留我的下拉菜单的现有交互性,其中单击/轻触会显示整个下拉内容块,单击内容块外部会关闭它。

我希望我的下拉菜单中的元素表示HTML页面的各种显示/隐藏<div>选项,并允许用户通过额外的单击/轻触选择它们(基本上是演示JS过滤器所做的事情,但由单击/轻触发起)。一旦通过导航栏的单击/轻触显示,整个下拉内容块必须保持在屏幕上,就像当前所做的那样,这才有可能。

在将我的下拉标识为id="media-selector-demo"和name="filter"后,我希望能够将演示JS过滤器的<option>元素分配给其中的<a>元素,然后整个事情会像演示JS过滤器的<select>下拉列表一样运作。我有一个模糊的想法,使用<a>元素可能不需要JS中的另一个onClick。我已经尝试了各种<a><option>元素的组合,但尚未取得任何进展。

我是否需要另一个onClick来通过我的下拉菜单调用JS过滤器?还是我可以通过活动的<a>状态调用JS过滤器?

我正在通过反复试验来解决这个问题。

以下是我认为与上述所有内容相关的代码部分:

我的下拉菜单基于以下代码。
页面头部的JS

  1. /* 当用户单击按钮时,切换隐藏和显示下拉内容 */
  2. function myDropdownJS() {
  3. document.getElementsByClassName("navbarDROPDOWN-JS")[0].classList.toggle("show");
  4. }
  5. // 如果用户单击内容之外的地方,关闭下拉菜单
  6. window.onclick = function(e) {
  7. if (!e.target.matches('.dropbtn')) {
  8. var myDropdown = document.getElementsByClassName("navbarDROPDOWN-JS")[0];
  9. if (myDropdown.classList.contains('show')) {
  10. myDropdown.classList.remove('show');
  11. }
  12. }
  13. }

我的下拉菜单HTML在导航栏中(大部分CSS只是设计样式):

  1. <span class="dropdown" onclick="myFunction()">
  2. <a class="dropbtn navbarDROP-ICON" style="opacity:0.5; padding-top:0px;">menu</a>
  3. <a class="dropbtn navbarDROP-TXT" style="opacity:0.5">menu&nbsp;&nbsp;</a>
  4. <a class="dropbtn navbarDROP-TXT">Career Works by Date&nbsp;&nbsp;</a>
  5. <div class="dropdown-content navbarDROPDOWN-JS" >
  6. <a class="tag-bgd-INSTLLN" href="#">Installations (all media)</a>
  7. <a class="tag-bgd-MOVIMG" href="#">Works with moving image (inc. vid/film releases)</a>
  8. <a class="tag-bgd-SNDMUS" href="#">...with sound and music (inc. sound/music releases)</a>
  9. <a class="tag-bgd-PHOTO" href="#">...with photographs</a>
  10. <a class="tag-bgd-DRAW" href="#">...with drawing (inc. 2D works)</a>
  11. <a class="tag-bgd-TXT" href="#">...with text</a>
  12. <a class="tag-bgd-PERF" href="#">...with performative action</a>
  13. <a class="tag-bgd-COLPUB" href="#">Collaborative and public works</a>
  14. <a class="tag-bgd-OBJDEV" href="Objects, garments, devices</a>
  15. <a class="tag-bgd-EDPUB" href="Editions, publications</a>
  16. <a class="tag-bgd-CAREER" href="#">Career Works by Date</a>
  17. </div>

上述<a href>元素将包含不同样式页面的URL。如果我可以通过此下拉菜单使用户有选择地显示/隐藏页面的不同部分,那么就不需要这些URL。

演示JS过滤器基于以下代码(通过SO用户the.marolie提供)。
页面末尾的JS

  1. var select = document.getElementById('media-selector-demo');
  2. var filter;
  3. select.addEventListener("change", function() {
  4. filter = select.value;
  5. var elements = document.querySelectorAll('.wk-date_ITEM');
  6. elements.forEach((el) => {
  7. var type = el.dataset.type.split(', ');
  8. if (type.includes(filter)) {
  9. el.classList.remove('hide-by-media');
  10. } else {
  11. el.classList.add('hide-by-media');
  12. }
  13. })
  14. });

演示JS过滤器CSS

  1. .hide-by-media {
  2. display: none;
  3. }

演示JS过滤器的页面主体中的HTML

  1. <select id="media-selector-demo" name="filter">
  2. <option value="INSTLLN"> Installations (all media)</option>
  3. <option value="MOVIMG"> Works with moving image (inc. vid/film releases)</option>
  4. <option value="SNDMUS"> ...with sound and music (inc. sound/music releases)</option>
  5. </select>

示例页面主体中的div(共有80-100个):

  1. <!-- ++++++++++ START FULL-WIDTH LIST ENTRY '2017 STATE OF DREAD' ++++++++++ -->
  2. <div id="state-of-dread" class="w3-container wk-date_ITEM" data-type="INSTLLN, SNDMUS">
  3. <div class="w3-container wk-date_TXT-IMG">
  4. <div class="wk-date_GRID
  5. <details>
  6. <summary>英文:</summary>
  7. With the help of SO member the.marolie I learned how to implement a JS filter/selector [the &#39;demo JS filter&#39;]. I have this working perfectly on a test page: it shows/hides divs according to &quot;data-types&quot; assigned to them in the body html. However, the selection is made by sliding down a `&lt;select&gt;` dropdown list and letting go at the preferred option. That&#39;s not quite what I want.
  8. I want to utilise my existing nav-bar dropdown [&#39;my dropdown&#39;] as the filter/selector. I especially want to retain the existing interactivity of my dropdown, whereby one click/tap reveals the whole of the dropdown content block, and one click outside the content block closes it.
  9. I want the elements within my dropdown to represent various show/hide `&lt;div&gt;` &#39;options&#39; for the html page, and enable the user to choose from these via an additional click/tap (essentially what the demo JS filter does, but at the instigation of a click/tap). Once revealed via a nav-bar click/tap, the whole dropdown content block has to stay on-screen -as it currently does- for this to be practically possible.
  10. After making my dropdown identifiable via id=&quot;media-selector-demo&quot; and name=&quot;filter&quot; I was hoping that I could assign the demo JS filter&#39;s `&lt;option&gt;` elements to the `&lt;a&gt;` elements in it, and the whole thing would function like the `&lt;select&gt;` dropdown of the demo JS filter. I had a vague idea that using `&lt;a&gt;` elements might obviate the need for another `onClick` in the JS. I&#39;ve tried various combinations of `&lt;a&gt;` and `&lt;option&gt;` elements, but nothing has worked yet.
  11. Do I need another `onClick` to invoke the JS filter via my dropdown? or
  12. Can I invoke the JS filter via &#39;active&#39; `&lt;a&gt;` status?
  13. I&#39;m struggling by trial and error.
  14. Here are what I think are the relevant sections of code pertaining to all discussed above:
  15. **My dropdown** is based on the following code.
  16. **JS** in the page head:

/* When the user clicks on the button,
toggle between hiding and showing the dropdown content */
function myDropdownJS() {
document.getElementsByClassName("navbarDROPDOWN-JS")[0].classList.toggle("show");
}

// Close the dropdown if the user clicks outside of it
window.onclick = function(e) {
if (!e.target.matches('.dropbtn')) {
var myDropdown = document.getElementsByClassName("navbarDROPDOWN-JS")[0];
if (myDropdown.classList.contains('show')) {
myDropdown.classList.remove('show');
}
}
}

  1. **My dropdown** **html** in nav bar (most of the css is just design styling):

<span class="dropdown" onclick="myFunction()">
<a class="dropbtn navbarDROP-ICON" style="opacity:0.5; padding-top:0px;">menu</a>
<a class="dropbtn navbarDROP-TXT" style="opacity:0.5">menu&nbsp;&nbsp;</a>
<a class="dropbtn navbarDROP-TXT">Career Works by Date&nbsp;&nbsp;</a>
<div class="dropdown-content navbarDROPDOWN-JS" >
<a class="tag-bgd-INSTLLN" href="#">Installations (all media)</a>
<a class="tag-bgd-MOVIMG" href="#">Works with moving image (inc. vid/film releases)</a>
<a class="tag-bgd-SNDMUS" href="#">...with sound and music (inc. sound/music releases)</a>
<a class="tag-bgd-PHOTO" href="#">...with photographs</a>
<a class="tag-bgd-DRAW" href="#">...with drawing (inc. 2D works)</a>
<a class="tag-bgd-TXT" href="#">...with text</a>
<a class="tag-bgd-PERF" href="#">...with performative action</a>
<a class="tag-bgd-COLPUB" href="#">Collaborative and public works</a>
<a class="tag-bgd-OBJDEV" href="#">>Objects, garments, devices</a>
<a class="tag-bgd-EDPUB" href="#">Editions, publications</a>
<a class="tag-bgd-CAREER" href="#">Career Works by Date</a>
</div>

  1. Above: the `&lt;a href&gt;` elements were going to contain URLs for alternatively styled pages. There is no need for these if I can enable the user to selectively show/hide parts of just this one page, via this dropdown.
  2. The **demo JS filter** is based on the following code (via SO user the.marolie).
  3. **JS** at page end:

var select = document.getElementById('media-selector-demo');
var filter;

select.addEventListener("change", function() {
filter = select.value;

var elements = document.querySelectorAll('.wk-date_ITEM');
elements.forEach((el) => {
var type = el.dataset.type.split(', ');
if (type.includes(filter)) {

  1. el.classList.remove(&#39;hide-by-media&#39;);
  2. } else {
  3. el.classList.add(&#39;hide-by-media&#39;);
  4. }

})
});

  1. **Demo JS filter** **CSS**:

.hide-by-media {
display: none;
}

  1. **Demo JS filter** **html** in page body:

<select id="media-selector-demo" name="filter">
<option value="INSTLLN"> Installations (all media)</option>
<option value="MOVIMG"> Works with moving image (inc. vid/film releases)</option>
<option value="SNDMUS" >...with sound and music (inc. sound/music releases)</option>
</select>

  1. Example **div in page body** (there are 80-100 of these):

<!-- ++++++++++ START FULL-WIDTH LIST ENTRY '2017 STATE OF DREAD' ++++++++++ -->
<div id="state-of-dread" class="w3-container wk-date_ITEM" data-type="INSTLLN, SNDMUS">
<div class="w3-container wk-date_TXT-IMG">
<div class="wk-date_GRID">

  1. &lt;div class= &quot;h3 wk-date_DATE&quot;&gt; 2017 &lt;/div&gt;
  2. &lt;div class=&quot;wk-date_TTL&quot;&gt;&lt;h1&gt;State of Dread&lt;/h1&gt;&lt;/div&gt;
  3. &lt;div class=&quot;h2 wk-date_KIND-1&quot; &gt;Installation&lt;/div&gt;
  4. &lt;div class=&quot;p wk-date_KIND-2&quot; &gt;&lt;span class=&quot;sound&quot;&gt;Sound&lt;/span&gt;, for x2 interconnected rooms.&lt;br&gt;AB, CD, EF, Solo exhibition (as trio), Ohrenhoch sound gallery, Berlin.&lt;/div&gt;
  5. &lt;div class=&quot;wk-date_IMG&quot;&gt;
  6. &lt;div class=&quot;w3-container w3-right wk-date_IMG-BOX-LSCP&quot;&gt;
  7. &lt;img src=&quot;../../imgs/INSTALLATION-EVENT/2017_dread_thmb.jpg&quot;
  8. alt=&quot;&#39;xx&#39; by Andrew Stones, installation view, xx&quot;&gt;&lt;/div&gt;
  9. &lt;/div&gt;
  10. &lt;/div&gt;
  11. &lt;/div&gt;

</div>
<!-- ++++++++++ END FULL-WIDTH LIST ENTRY '2017 STATE OF DREAD' ++++++++++ -->

  1. **Demo JS filter**: **JS** at end of page:

<script type="text/javascript">
var select = document.getElementById('media-selector-demo');
var filter;

select.addEventListener("change", function() {
filter = select.value;

var elements = document.querySelectorAll('.wk-date_ITEM');
elements.forEach((el) => {
var type = el.dataset.type.split(', ');
if (type.includes(filter)) {
el.classList.remove('hide-by-media');
} else {
el.classList.add('hide-by-media');
}

})
});
</script>

  1. </details>
  2. # 答案1
  3. **得分**: 0
  4. 你需要做的是将事件侦听器从`select, change`更改为`下拉元素, 点击`,还需要将选择框中选项的值作为`data-value`属性添加到下拉元素上。
  5. 1 - 为表示要隐藏的元素添加一个`data-value`属性
  6. <a class="tag-bgd-INSTLLN" href="#" data-value="INSTLLN">
  7. 2 - 目标是要附加事件侦听器的下拉元素。
  8. const dropDownElements = document.querySelectorAll('.dropdown-content a')
  9. 3 - 附加事件侦听器到所选目标(PS. 函数中的`e`代表事件,点击事件侦听器生成一个事件对象)
  10. dropDownElements.forEach((dropDownElement) => {
  11. dropDownElement.addEventListener('click',(e)=>{
  12. const filter = e.target.dataset.value;
  13. })
  14. })
  15. 4 - 其余部分只是添加在**演示js过滤器**中使用的其余过滤器
  16. dropDownElements.forEach((dropDownElement) => {
  17. dropDownElement.addEventListener("click", (e) => {
  18. const filter = e.target.dataset.value
  19. var elements = document.querySelectorAll(".wk-date_ITEM")
  20. elements.forEach((el) => {
  21. var type = el.dataset.type.split(", ")
  22. if (type.includes(filter)) {
  23. el.classList.remove("hide-by-media")
  24. } else {
  25. el.classList.add("hide-by-media")
  26. }
  27. })
  28. })
  29. })
  30. <details>
  31. <summary>英文:</summary>
  32. What you would need to do is change the event listener from `select, change` to `drop down element, click`. you would also need to add the values of the options from the select as data-value attributes on the drop down elements.
  33. 1 - add a data-value attribute to the elements to represent what to hide
  34. &lt;a class=&quot;tag-bgd-INSTLLN&quot; href=&quot;#&quot; data-value=&quot;INSTLLN&quot;&gt;
  35. 2 - target the drop down elements you want to attach the event listener to.
  36. const dropDownElements = document.querySelectorAll(&#39;.dropdown-content a&#39;)
  37. 3 - attach event listeners to the selected targets (PS. the e in the function stands for event, click event listener produces an event object)
  38. dropDownElements.forEach((dropDownElement) =&gt; {
  39. dropDownElement.addEventListener(&#39;click&#39;,(e)=&gt;{
  40. const filter = e.target.dataset.value;
  41. })
  42. })
  43. 4 - the rest is just adding the rest of the filter used in the **demo js filter**
  44. dropDownElements.forEach((dropDownElement) =&gt; {
  45. dropDownElement.addEventListener(&quot;click&quot;, (e) =&gt; {
  46. const filter = e.target.dataset.value
  47. var elements = document.querySelectorAll(&quot;.wk-date_ITEM&quot;)
  48. elements.forEach((el) =&gt; {
  49. var type = el.dataset.type.split(&quot;, &quot;)
  50. if (type.includes(filter)) {
  51. el.classList.remove(&quot;hide-by-media&quot;)
  52. } else {
  53. el.classList.add(&quot;hide-by-media&quot;)
  54. }
  55. })
  56. })
  57. })
  58. </details>

huangapple
  • 本文由 发表于 2023年2月16日 01:57:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/75463722.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定