简体   繁体   中英

Best way to find nearest href attribute?

Why I don't think it's a duplicate.

Hmm, I think that's slightly different to what I'm asking. I don't want to add a listener to all A tags, rather, substract an href attribute, if any, on a click event's target.

I'm trying to "Ajaxify" my whole site, so that when an user clicks ANY link contained within the page, a script sends the "url" or HREF attribute (of the clicked element) to an Ajax function, which in return, renders the requested content (as indicated by the link clicked).

I need to find the HREF attribute of the clicked element, if the element is a link. The problem here , is that many elements can be contained within an A tag (because of the way I've structured them), and e.target.href doesn't necessarily always return an HREF attribute.

Here is what I have so far:

function ajaxifyLinks(e) {
    var target = e.target;
    e.preventDefault();
    while(!target.href) {
        target = target.parentNode;
    }
    if(target.href) {
        ajaxLoad(target.href);
    }
}
document.body.addEventListener('click', ajaxifyLinks);

And here are examples of different "clickable" links that I have:

<!-- Link -->
<a href="/cats">
   cats
</a>

<!-- Link -->
<a href="/hello">
   <span>
      <span> hi </span>
   </span>
</a>

<!-- Link -->
<a href="/bye">
   <span>
      bye
   </span>
</a>

As you can see, this is why e.target.href won't always return the HREF attribute, because you are actually clicking a "linked" span element, however, the browser does take you to the link. Why does this happen? And is there any way I can benefit from that behavior? (As in, extracting the location where the browser is taking you, even if you aren't clicking over an A tag).

I don't like my solution, because the while loop just keeps looking up the DOM tree, sometimes needlessly (when e.target isn't a link or contained by a link).

Thanks.

If the element clicked does not have an href, it searches it's parents for an element that has an href. Vanilla JS solution.

 function findUpTag(el, attr) { while (el.parentNode) { el = el.parentNode; if (el[attr]) { return el; } } return null; } document.body.onclick = function (event) { event.preventDefault(); var href = event.target.href; if (!href) { var closest = findUpTag(event.target, 'href'); if (closest) { href = closest.href; } } document.getElementById('output').innerHTML = 'element clicked: ' + event.target.nodeName + '<br>closest href: ' + href; }; 
 a, output { display: block; } 
 <!-- Link --> <a href="/cats"> cats </a> <!-- Link --> <a href="/hello"> <span> <span> hi </span> </span> </a> <!-- Link --> <a href="/bye"> <span> bye </span> </a> <output id="output"></output> 

New answer:

 <!-- Link --> <a href="/cats"> cats </a> <!-- Link --> <a href="/hello"> <span style="pointer-events: none;"> <span style="pointer-events: none;"> hi </span> </span> </a> <!-- Link --> <a href="/bye"> <span style="pointer-events: none;"> bye </span> </a> 

Use the .parent() , ref: http://api.jquery.com/parent/

for example, you can do

 var hrefElem = $(target).parent('*[href]'); var link = hrefElem.attr('href'); 

Just attach a click handler to each link on the page:

function ajaxify(e)
{
    e.preventDefault();
    ajaxLoad(this.href);
}

[].forEach.call(document.getElementsByTagName('a'), function(el) {
    el.addEventListener('click', ajaxify.bind(el));
});

Have a look at What is event bubbling and capturing? to understand how events propagate through the DOM.

The technique of capturing anchor links and loading them via Ajax is referred to as Hijax . Because you're replacing content on the page, you can't simply set up a single event to handle all links, and you probably don't want to keep re-binding every page load, so the approach you are using is good, and is known as event delegation .

The last article describes exactly your problem (right at the very end), and also describes a solution similar to yours, which is really the best way to do it in this scenario. However, you could look at using a microlibrary to simplify some of the event delegation; one example is gator.js .

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