简体   繁体   English

在Vanilla JavaScript中,如何显示/隐藏<span>多个类名?</span>

[英]In Vanilla JavaScript, how do I show/hide <span>s with multiple class names?

So, say I have this in my body section of my HTML5 doc: 所以,说我在HTML5文档的正文部分中有此内容:

    <p><input type="checkbox" checked onchange="ShowHide('Book1', this);"> Book 1</p>
    <p><input type="checkbox" checked onchange="ShowHide('Book2', this);"> Book 2</p>
    <p><span class="Book1">Show when Book 1 is checked. </span>
       <span class="Book2">Show when Book 2 is checked. </span>
       <span class="Book1 Book2">Show when either Book 1 or Book 2, or both are checked. </span></p>

with the following script in a seperate JS file: 在单独的JS文件中使用以下脚本:

function ShowHide(a, b) {
    var vis = (b.checked) ? "" : "none";
    var book = document.getElementsByClassName(a);
    for (var i = 0; i < book.length; i++) {
        book[i].style.display = vis;
    }   
}

It will show/hide the 'book content' for 1 & 2 just fine. 它将显示/隐藏1和2的“书本内容”。 But I want the content that has both class names, to show up, if either one or both are checked. 但是,如果选中一个或两个都选中,我希望同时显示具有两个类名的内容。 But not if they both aren't selected. 但是,如果未同时选择它们,则不会。 With 2 books, I can write out every scenario, but with 13+ books this is quite impossible. 有2本书,我可以写出每种情况,但有13本书以上,这是完全不可能的。 Any ideas on how to do this? 有关如何执行此操作的任何想法? Any insight would be highly appreciated! 任何见解将不胜感激!

This is a little tricky. 这有点棘手。 You need to check every span (or at least every span that matches the toggled checkbox) to see if it matches any of the currently checked checkboxes. 您需要检查每个范围(或至少每个与切换的复选框匹配的范围),以查看它是否与任何当前选中的复选框匹配。

Your current approach is to use JavaScript to identify which elements to show and hide. 您当前的方法是使用JavaScript识别要显示和隐藏的元素。 To do that you would need to: 为此,您需要:

  • Gather a list of all the currently checked checkbox values 收集所有当前选中的复选框值的列表
  • Gather a list of all the span elements 收集所有span元素的列表
  • Loop over all the span elements and see if they match any of the checkbox values in the list (with indexOf ) hiding or showing them as appropriate 循环遍历所有span元素,查看它们是否与列表中的任何复选框值匹配(带有indexOf ),以适当地隐藏或显示它们

This isn't difficult, but it involves a lot of looping and is rather tedious. 这并不困难,但是涉及很多循环并且非常乏味。

I'd approach this in a slightly different way: 我会以一种稍微不同的方式来处理这个问题:

Modify the class of a parent container and use CSS to control what is visible or not. 修改父容器的类,并使用CSS来控制可见或不可见的内容。

Moving the problem of deciding how to combine the various "Display this" instructions to CSS makes life a lot easier. 将决定如何将各种“显示此”指令组合到CSS的问题转移到生活中会容易得多。

 document.getElementById('checkboxes').addEventListener('click', showHide); function showHide(e) { if (e.target.type !== "checkbox") { return; } var b = document.getElementById('books'); if (e.target.checked) { b.classList.add("show-" + e.target.value); } else { b.classList.remove("show-" + e.target.value); } } 
 #books p { display: none; } #books.show-book1 .book1 { display: block; } #books.show-book2 .book2 { display: block; } 
 <div id="checkboxes"> <label> <input type="checkbox" value="book1" />Book1</label> <label> <input type="checkbox" value="book2" />Book2</label> </div> <div id="books"> <p class="book1">One</p> <p class="book2">Two</p> <p class="book1 book2">Both</p> </div> 

The downside with this approach is writing out a CSS ruleset for each book class. 这种方法的缺点是为每个书类写了一个CSS规则集。 You could generate them programatically (SASS, for instance, makes generating this sort of set of similar rules very easy). 您可以以编程方式生成它们(例如,SASS使得生成这种相似规则集非常容易)。

I think an elegant solution is to keep a reference count of filters checked directly on the element using data attributes . 我认为一个不错的解决方案是使用data属性直接在元素上检查过滤器的引用计数。

Every time a checkbox is clicked, associated items are iterated, and their reference count updated. 每次单击复选框,都会迭代关联的项目,并更新其引用计数。 Any element with no references is hidden. 任何没有引用的元素都是隐藏的。 This keeps your runtime to a single loop, and is very scalable. 这样可以将运行时保持在单个循环中,并且具有很高的可伸缩性。

 function checker (e) { var ref, dir, itemset; if (e.target.type === 'checkbox') { dir = e.target.checked ? 1 : -1; itemset = document.getElementsByClassName(e.target.value); Array.prototype.forEach.call(itemset, function (el) { ref = dir + parseInt(el.getAttribute('data-ref'), 10); el.setAttribute('data-ref', ref); el.style.display = ref > 0 ? 'block' : 'none'; }); } } document .getElementById('checks') .addEventListener('click', checker); 
 .item { display: none; } 
 <div id="checks"> <input type="checkbox" value="one"> <input type="checkbox" value="two"> <input type="checkbox" value="three"> </div> <div id="items"> <div class="item one" data-ref="0">one</div> <div class="item two" data-ref="0">two</div> <div class="item three" data-ref="0">three</div> <item class="item one two" data-ref="0">one-two</item> </div> 

This is a little bit dirty, but it seems to work : 这有点脏,但似乎可以正常工作:
Caveat : you have to append a class to the inputs, could also be a data-attribute : 警告:您必须在输入中添加一个类,也可能是数据属性:

If the changed input is not checked, it will loop through the spans that have the same className, and check if they've got an other className. 如果未选中更改的输入,它将循环遍历具有相同className的跨度,并检查它们是否具有其他className。 If they do, then it will check if the other input that have this className is checked or not. 如果是这样,它将检查是否选中了具有此类className的其他输入。

 function ShowHide(inp) { var vis = inp.checked; var spans = document.querySelectorAll('span.' + inp.className); for (var i = 0; i < spans.length; i++) { if (!vis) { var this_vis; var classes = spans[i].className.split(' '); for (var c = 0; c < classes.length; c++) { this_vis = document.querySelector('input.' + classes[c]).checked; if (this_vis) break; } } spans[i].style.display = this_vis || vis ? '' : 'none'; } } 
 <p> <input class="Book1" type="checkbox" checked onchange="ShowHide(this)">Book 1</p> <p> <input class="Book2" type="checkbox" checked onchange="ShowHide(this)">Book 2</p> <p><span class="Book1">Show when Book 1 is checked. </span> <span class="Book2">Show when Book 2 is checked. </span> <span class="Book1 Book2">Show when either Book 1 or Book 2, or both are checked. </span> </p> 

I have put the data in an array. 我已经将数据放在一个数组中。 Also it has a show flag specifying the content to show. 它还具有一个show标志,用于指定要显示的内容。

var bookData = [
                {id: 1, name: "book 1", content: 'Show when Book 1 is checked.', show: [1, 2, 3]},
                {id: 2, name: "book 2", content: 'Show when Book 2 is checked.', show: [2]},
                {id: 3, name: "book 3", content: 'Show when Book 3 is checked.', show: [2, 3]},
                {id: 4, name: "book 4", content: 'Show when Book 4 is checked.', show: [1, 3, 4]},
                {id: 5, name: "book 5", content: 'Show when Book 5 is checked.', show: [2, 4, 5]}
            ];
 function ShowHide(a, b, c) {
                var vis = (b.checked) ? "" : "none";
                var book = document.getElementsByClassName('books');
                console.log(c);
                var el = [];
                for(var j = 0; j < book.length; j++) {
                    book[j].style.display = 'none';
                }
                for (var i = 0; i < c.length; i++) {
                    var clsname = 'book-'+ c[i];

                    el.push(document.getElementById(clsname)) ;
                    console.log(el);
                    el[i].style.display = vis;
                }
            }
            function showBooks() {
                var data = '',
                        cont=  '';
                for(var i = 0; i < bookData.length; i++) {
                    var showItems = '';
                    var items = [];
                    for(var j = 0; j < bookData[i].show.length; j++) {
                        showItems += 'Book' + bookData[i].show[j] + ' ';
                        items.push(bookData[i].show[j]);
                    }
                    data+= '<p><input id="bkid-'+ bookData[i].id+'" type="checkbox" onchange="ShowHide('+'\'Book'+bookData[i].id+'\', this, ['+ items +']);" >'+ bookData[i].name+'</p>';

                    cont += '<p><span class="books" id="book-'+bookData[i].id+'">'+bookData[i].content+'</span>';
                }
                document.getElementById("box").innerHTML = data + cont;
            }

showBooks();

In this way the code remains dynamic, and we can feed as much data of books we want. 这样,代码将保持动态状态,并且我们可以提供所需数量的书籍数据。 working fiddle 工作小提琴

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM