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评论68阅读模式
英文:

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

/* 当用户单击按钮时,切换隐藏和显示下拉内容 */
function myDropdownJS() {
  document.getElementsByClassName("navbarDROPDOWN-JS")[0].classList.toggle("show");
}

// 如果用户单击内容之外的地方,关闭下拉菜单
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');
    }
  }
}

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

<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>

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

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

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

  })
});

演示JS过滤器CSS

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

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

<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>   

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

<!-- ++++++++++ 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

<details>
<summary>英文:</summary>

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.

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.

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.


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.

Do I need another `onClick` to invoke the JS filter via my dropdown? or
Can I invoke the JS filter via &#39;active&#39; `&lt;a&gt;` status? 

I&#39;m struggling by trial and error. 

Here are what I think are the relevant sections of code pertaining to all discussed above: 

**My dropdown** is based on the following code.
**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');
}
}
}

**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>

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.

The **demo JS filter** is based on the following code (via SO user the.marolie).
**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)) {

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

})
});

**Demo JS filter** **CSS**:

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

**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>


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">

      &lt;div class= &quot;h3 wk-date_DATE&quot;&gt; 2017 &lt;/div&gt;
      &lt;div class=&quot;wk-date_TTL&quot;&gt;&lt;h1&gt;State of Dread&lt;/h1&gt;&lt;/div&gt;
     &lt;div class=&quot;h2 wk-date_KIND-1&quot; &gt;Installation&lt;/div&gt;
      &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;
      &lt;div class=&quot;wk-date_IMG&quot;&gt;
      &lt;div class=&quot;w3-container w3-right wk-date_IMG-BOX-LSCP&quot;&gt;
      &lt;img src=&quot;../../imgs/INSTALLATION-EVENT/2017_dread_thmb.jpg&quot;
      alt=&quot;&#39;xx&#39; by Andrew Stones, installation view, xx&quot;&gt;&lt;/div&gt;
      &lt;/div&gt;
   
	&lt;/div&gt;
&lt;/div&gt;

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


**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>





</details>


# 答案1
**得分**: 0

你需要做的是将事件侦听器从`select, change`更改为`下拉元素, 点击`,还需要将选择框中选项的值作为`data-value`属性添加到下拉元素上。

1 - 为表示要隐藏的元素添加一个`data-value`属性

   <a class="tag-bgd-INSTLLN" href="#" data-value="INSTLLN">

2 - 目标是要附加事件侦听器的下拉元素。

   const dropDownElements = document.querySelectorAll('.dropdown-content a')

3 - 附加事件侦听器到所选目标(PS. 函数中的`e`代表事件,点击事件侦听器生成一个事件对象)

   dropDownElements.forEach((dropDownElement) => {
       dropDownElement.addEventListener('click',(e)=>{
           const filter = e.target.dataset.value;
       })
   })

4 - 其余部分只是添加在**演示js过滤器**中使用的其余过滤器

   dropDownElements.forEach((dropDownElement) => {
       dropDownElement.addEventListener("click", (e) => {
           const filter = e.target.dataset.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")
               }
           })
       })
   })

<details>
<summary>英文:</summary>

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.

1 - add a data-value attribute to the elements to represent what to hide

     &lt;a class=&quot;tag-bgd-INSTLLN&quot; href=&quot;#&quot; data-value=&quot;INSTLLN&quot;&gt;

2 - target the drop down elements you want to attach the event listener to.

    const dropDownElements = document.querySelectorAll(&#39;.dropdown-content a&#39;)

3 - attach event listeners to the selected targets (PS. the e in the function stands for event, click event listener produces an event object)

    dropDownElements.forEach((dropDownElement) =&gt; {
    	dropDownElement.addEventListener(&#39;click&#39;,(e)=&gt;{
    		const filter = e.target.dataset.value;
    	})
    })

4 - the rest is just adding the rest of the filter used in the **demo js filter**

    dropDownElements.forEach((dropDownElement) =&gt; {
    	dropDownElement.addEventListener(&quot;click&quot;, (e) =&gt; {
    		const filter = e.target.dataset.value
    		var elements = document.querySelectorAll(&quot;.wk-date_ITEM&quot;)
    		elements.forEach((el) =&gt; {
    			var type = el.dataset.type.split(&quot;, &quot;)
    			if (type.includes(filter)) {
    				el.classList.remove(&quot;hide-by-media&quot;)
    			} else {
    				el.classList.add(&quot;hide-by-media&quot;)
    			}
    		})
    	})
    })

</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:

确定