web-dev-qa-db-fra.com

Faire en sorte que les liens d’ancre se rapportent à la page en cours avec <base>

Lorsque j'utilise la balise html <base> pour définir une URL de base pour tous les liens relatifs d'une page, les liens d'ancrage font également directement référence à l'URL de base. Y a-t-il un moyen de définir l'URL de base qui permettrait toujours aux liens d'ancrage de faire référence à la page actuellement ouverte?

Par exemple, si j'ai une page à http://example.com/foo/:


Comportement actuel:

<base href="http://example.com/" />
<a href="bar/">bar</a> <!-- Links to "http://example.com/bar/" -->
<a href="#baz">baz</a> <!-- Links to "http://example.com/#baz" -->

Comportement souhaité:

<base href="http://example.com/" />
<a href="bar/">bar</a> <!-- Links to "http://example.com/bar/" -->
<a href="#baz">baz</a> <!-- Links to "http://example.com/foo/#baz" -->
38
Chris Down

j'ai trouvé une solution sur ce site: using-base-href-with-anchors qui ne nécessite pas jQuery et voici un extrait fonctionnel:

<base href="https://example.com/">

<a href="/test">/test</a>
<a href="javascript:;" onclick="document.location.hash='test';">Anchor</a>

ou sans js en ligne, quelque chose comme ceci:

document.addEventListener('DOMContentLoaded', function(){
  var es = document.getElementsByTagName('a')
  for(var i=0; i<es.length; i++){
    es[i].addEventListener('click', function(e) {
      e.preventDefault()
      document.location.hash = e.target.getAttribute('href')
    })
  }
})
20
davide bubz

S'appuyant sur la réponse de @James Tomasino, celle-ci est légèrement plus efficace, résout un bogue avec des doubles hachages dans l'URL et une erreur de syntaxe.

$(document).ready(function() {
    var pathname = window.location.href.split('#')[0];
    $('a[href^="#"]').each(function() {
        var $this = $(this),
            link = $this.attr('href');
        $this.attr('href', pathname + link);
    });
});
11

Un peu de jQuery pourrait probablement vous aider avec ça. Bien que href de base fonctionne comme vous le souhaitez, si vous souhaitez que vos liens commençant par une ancre (#) soient totalement relatifs, vous pouvez détourner tous les liens, vérifier la propriété href pour ceux commençant par # et les reconstruire à l'aide de l'URL actuelle.

$(document).ready(function () {
    var pathname = window.location.href;
    $('a').each(function () {
       var link = $(this).attr('href');
       if (link.substr(0,1) == "#") {
           $(this).attr('href', pathname + link);
       }
    });
}
7
James Tomasino

Voici une version encore plus courte, basée sur jQuery, que j’utilise dans un environnement de production et qui fonctionne bien pour moi.

$().ready(function() {
  $("a[href^='\#']").each(function(){ 
    this.href=location.href.split("#")[0]+'#'+this.href.substr(this.href.indexOf('#')+1);
  });
});
2
contendia

Si vous utilisez PHP, vous pouvez utiliser la fonction suivante pour générer des liens d'ancrage:

function generateAnchorLink($anchor) {
  $currentURL = "//{$_SERVER['HTTP_Host']}{$_SERVER['REQUEST_URI']}";
  $escaped = htmlspecialchars($currentURL, ENT_QUOTES, 'UTF-8');
  return $escaped . '#' . $anchor;
}

Utilisez-le dans le code comme ça:

<a href="<?php echo generateAnchorLink("baz"); ?>">baz</a>
1

Vous pouvez également fournir une URL absolue:

<base href="https://example.com/">
<a href="/test#test">test</a>

Plutôt que cela

<a href="#test">test</a>
0
atoms

Je crains qu'il n'y ait aucun moyen de résoudre ce problème sans un script côté serveur ou côté navigateur. Vous pouvez essayer l'implémentation JavaScript suivante (sans jQuery):

document.addEventListener("click", function(event) {
  var element = event.target;
  if (element.tagName.toLowerCase() == "a" && 
      element.getAttribute("href").indexOf("#") === 0) {
    element.href = location.href + element.getAttribute("href");
  }
});
<base href="https://example.com/">

<a href="/test">/test</a>
<a href="#test">#test</a>

Cela fonctionne également (contrairement aux autres réponses) pour les éléments a générés dynamiquement (c.-à-d. Créés avec JavaScript).

0

Pour empêcher plusieurs URL dans #:

         document.addEventListener("click", function(event) {
          var element = event.target;
          if (element.tagName.toLowerCase() == "a" && 
            element.getAttribute("href").indexOf("#") === 0) {
            my_href = location.href + element.getAttribute("href");
            my_href = my_href.replace(/#+/g, '#');
            element.href = my_href;
          }
        });
0
Yektaweb Company

De l'exemple donné dans la question. Pour obtenir le comportement souhaité, je ne vois pas la nécessité d'utiliser la balise "base".

La page est à http://example.com/foo/

Le code ci-dessous donnera le comportement souhaité:

<a href="/bar/">bar</a> <!-- Links to "http://example.com/bar/" -->
<a href="#baz">baz</a> <!-- Links to "http://example.com/foo/#baz" -->

L'astuce consiste à utiliser "/" au début de la chaîne href = "/ bar /".

0
Steve Kang