简体   繁体   中英

Open all external links open in a new tab apart from a domain

I'm trying to open all external links on a site in a new window. However on there are 2 versions of the site, eg a store and the main site. So on the main site we might have links that go to http://store.example.com for example.

I've got some code here which will allow me to open all the external links in a new window. However I'd like to be able to exclude certain domains. Like the one I've mentioned above.

Here is the code:

$(document).ready(function() {
   $("a[href^=http]").each(function(){
      if(this.href.indexOf(location.hostname) == -1) {
         $(this).attr({
            target: "_blank",
            title: "Opens in a new window"
         });
      }
   })
});

I'm new to JS / jQuery so any additional information would be brilliant.

For triggering the clicks programmatically, you can do something like:

$(document).ready(function() {

   $("a[href^=http]").each(function(){

      // NEW - excluded domains list
      var excludes = [
         'excludeddomain1.com',
         'excludeddomain2.com',
         'excluded.subdomain.com'
      ];
      for(i=0; i<excludes.length; i++) {
         if(this.href.indexOf(excludes[i]) != -1) {
            return true; // continue each() with next link
         }
      }

      if(this.href.indexOf(location.hostname) == -1) {

           // attach a do-nothing event handler to ensure we can 'trigger' a click on this link
           $(this).click(function() { return true; }); 

           $(this).attr({
               target: "_blank",
               title: "Opens in a new window"
           });

           $(this).click(); // trigger it
      }
   })
});

Are you able to edit the HTML to get a better hook for maybe a click event? If i need to separate certain links between internal or external i will apply a rel value on the HTML element.

    <a href="URL" rel="external">Link</a>

Then in your javascript

    $('a[rel="external"]').click( function(event) {
     event.stopPropagation();
     window.open( $(this).attr('href') );
     return false;
    });

EDIT: seeing as you already have a ton of links, how about this..

    var a = new RegExp('http:\/\/store.blah.com');

    $('a').each(function() {

      if(a.test(this.href)) {
        $(this).click(function(event) {
         event.preventDefault();
         event.stopPropagation();
         window.open(this.href, '_blank');
        });
      }

    });

if you just want all links that don't match your domain name:

var all_links = document.querySelectorAll('a');
for (var i = 0; i < all_links.length; i++){
       var a = all_links[i];
       if(a.hostname != location.hostname) {
               a.rel = 'noopener';
               a.target = '_blank';
       }
}

I think I would do it like this:

    $(document).ready(function() {
      $("a[href^=http]").each(function(){
         if(this.href.indexOf(location.hostname) == -1 && this.href.indexOf("store.domain.com") == -1 && this.href.indexOf("other.domain.rule") == -1) {
            $(this).attr({
               target: "_blank",
               title: "Opens in a new window"
           });
         }
       })
    });

It's kinda manual but, if you don't want to deal with splitting strings and arrays, this is the solution. I'm sure this will help.

Edit: And addition to this, you can use techfoobar's solution for triggering link clicks. That will help you with your websites performance.

Along the same lines as techfoobar's reply you can build a list of domains that should be left to open in the same window. You can do it in a more robust way though using regular expresions. If you just do a straight indexOf() check you will skip links that have matching subdomains but not matching domains, although you can leave out the '$' if you want to match the name anywhere in the href string.

This implementation should do what you want and there are minimal modifications to the code you have needed.

$(document).ready(function() {
    //populate this list with whatever domain names you want, the 
    //$ sign matches the end of the string, only top level domains are affected
    var whiteList = [/google.com\/$/, /stackoverflow.com\/$/];

   $("a[href^=http]").each(function(){
      if(this.href.indexOf(location.hostname) == -1) {

        //check if the href of the current link matches any of our patterns
        var href = this.href;
        if(whiteList.filter(function(x){return x.test(href)}).length == 0) {

         $(this).attr({
            target: "_blank",
            title: "Opens in a new window"
         });
        }
      }
   })
});

With this example, all links going to google.com and stackoverflow.com will be left to open in the existing page as well.

If you'd rather use an event handler on body than change the dom, I recommend something like this...

  // open external links in a new tab
  $('body').on('click','a',function(){
    var $a = $(this);
    var href = $a.attr('href');
    if (href.indexOf('/') == 0) return;  // ignore relative links
    var target = $a.attr('target') || "";
    if (target.length > 0) return; // ignore links with a target attribute already
    window.open(href, '_blank');  // open external links in a new tab
    return false;
  });

This will do the trick for all external domains using PHP

$(document).ready(function() {
   $("a[href^=http]").each(function(){

      // NEW - excluded domains list
      var excludes = [
         '<?php echo $_SERVER['HTTP_HOST']; ?>'
      ];
      for(i=0; i<excludes.length; i++) {
         if(this.href.indexOf(excludes[i]) != -1) {
            return true; // continue each() with next link
         }
      }

      if(this.href.indexOf(location.hostname) == -1) {

           // attach a do-nothing event handler to ensure we can 'trigger' a click on this link
           $(this).click(function() { return true; }); 

           $(this).attr({
               target: "_blank",
               title: "Opens in a new window"
           });

           $(this).click(); // trigger it
      }
   })
});

Building on Collin's answer in raw JS, which is very nice as it doesn't need Jquery (despite OP's question). I'd amend it to have the ability to exclude domains other than the current hostname though:

    var all_links = document.querySelectorAll('a');
    var excludes = ['domain1.com','www.domain1.com','domain2.com'];
    for (var i = 0; i < all_links.length; i++){
        var a = all_links[i];
        var found = false; 
        for(j=0; j<excludes.length; j++) {
                if(a.href.includes(excludes[j])) {
                    found = true;
                    break;  
                }
        }    
        if (!found) {
            a.rel = 'noopener'; a.target = 'external';
        }
    }        

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