简体   繁体   中英

Adding active class based on current URL

I am trying to add 'active' class on my link. It is saying

Uncaught TypeError: document.querySelectorAll(...).each is not a function

Here is my code:

const current = window.location.href;
document.querySelectorAll("#nav-tab a").each(function(){
    const $this = this;
    
    if($this.attr('href').indexOf(current) !== -1){
        $this.classList.add("active");
    }
});

Can you help me? Or is there a better way to add a class name based on the current URL? Thank you so much!

I think that you are mistaken jQuery and vanilla javascript

$.each is a jQuery function in you case you can use .forEach

$.attr is a jQuery function in you case you can use .getAttribute

 const current = "#test-3";//window.location.href; document.querySelectorAll("#nav-tab a").forEach((elem) => { if (elem.getAttribute('href').indexOf(current) !== -1) { elem.classList.add("active"); } });
 .active { color:red}
 <div id="nav-tab"> <a href="#test-1">Test 1</a> <a href="#test-2">Test 2</a> <a href="#test-3">Test 3</a> <a href="#test-4">Test 4</a> </div>

You have a few issues with your code. Your mainly confusing jQuery methods with regular native browser methods/conventions:

  1. You need to use .forEach() and not .each() . The .forEach() method is a method on the NodeList that querySelectorAll() returns.

  2. .attr() is not a valid method. To get an element's attribute you can use .getAttribute() . We can use .href here instead to get the href. Note that getAttribute("href") will retrieve the URL as it is in your mark-up, whereas .href will retrieve the full, eg, if you had href="/foo/bar" , .href will give https://example.com/foo/bar , whereas .getAttribute() will return just /foo/bar .

  3. Use the element parameter of the function instead of this . When you use .forEach() you're iterating over the elements in your NodeList (ie: the elements you selected), so you can access each using the first parameter of the forEach callback. The this value in the browser (if not in strict mode ) will default to window , so it won't be the element like you're expecting it to be:

const current = window.location.href;
document.querySelectorAll("#nav-tab a").forEach(function(elem){ 
    if(elem.href.includes(current)){
      elem.classList.add("active");
    }
});

I've also changed .indexOf(...) !== -1 to .includes() , which is a more modern way to check if a string contains another value.


I will point out that you can make your query selector more advanced, which will limit the number of elements you iterate:

const current = window.location.href;
document.querySelectorAll(`#nav-tab a[href*="${current}"]`).forEach(elem => { 
  elem.classList.add("active");
});

This uses the attribute selector a[href*=...] to select the a elements that have a href that contains the text in stored in current .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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