Override default behaviour for link ('a')

2019-01-14 11:34发布

问题:

I don't know if what I'm trying to accomplish is possible at all. I would like to override the default behaviour for all the anchor objects (A tag) for a given HTML page. I know I can loop through all the A elements and dynamically add an onclick call to each one of them from the body element onload method, but I'm looking for a more absolute solution. What I need is that all A elements get assigned an onclick action which calls a method that passes the element href property as an argument, so the following:

<a href="http://domain.tld/page.html">

Dynamically becomes:

<a href="http://domain.tld/page.html" onclick="someMethodName('http://domain.tld/page.html'); return false;">

Like I said, the ideal way to do this would be to somehow override the Anchor class altogether when the document loads. If it's not possible then I'll resort to the loop-through-all A elements method (which I already know how to do).

回答1:

If you don't want to iterate over all your anchor elements, you can simply use event delegation, for example:

document.onclick = function (e) {
  e = e ||  window.event;
  var element = e.target || e.srcElement;

  if (element.tagName == 'A') {
    someFunction(element.href);
    return false; // prevent default action and stop event propagation
  }
};

Check the above example here.



回答2:

Using jQuery:

$(function() {
    $("a").click(function() {
        return someMethodName($(this).attr('href'));
    });
});

function someMethodName(href)
{
    console.log(href);
    return false;
}


回答3:

window.onload = function() {
    var anchorElements = document.getElementsByTagName('a');
    for (var i in anchorElements)
        anchorElements[i].onclick = function() {
            alert(this.href);
            return false;
        }
}

This is about the simplest way to do it. Wrap in <script type="text/javascript">...</script> in the document head and it will run on page load.



回答4:

There is no way to override all anchor elements onlick event. You could add an onclick to the document body and have logic to see if the even propagated up from an anchor element, and perform the event in that case, but this solution could cause problems if your page is complex, and isn't propagating clicks in some cases.

I would stick with the getElementsByTagName solution if its feasible.



回答5:

Similar to Benji XVI's answer, but using querySelectorAll, within for instance a container div with class 'container' And using es6.

const $elems = document.querySelectorAll('.container a')
var elems = Array.from($elems)
elems.map(a => {
  a.onclick = (e) => {
    e.preventDefault()
    window.alert('Clicking external links is disabled')
  }
})


回答6:

CMS's solution is the best solution. Be sure to note that you can get better performance if you reference the function or check that needs to be run from a string stored within a protype property set on base anchor/element or declaratively on the anchor/element. By using this property the function you want to call can be found and be called from one decision branch as opposed to writing a new decision branch for every possibility. If you break or use a case statement with more than one or two cases you should start considering this, today may be a good day to spot for inversion of control and injection style of coding.

Again, Do not use a case if there are multiple events you need to handle. Use instead string composition to construct the path to the function that needs to be called. This requires a prototype to be added to your "A" elements that define the default and string to be composed. A data-attribute on the element should be able to override the default. Essentially we just want a message and an action to pass by default and be changed declaritively in the markup. The action specified should be published somewhere as an API or other accessable library function and be callable by lib['funName']. Just give it an attribute, no worry of name or id. The prototype and attribute will be usefull for debounce, because you will have to debounce.

There is some guys working on clientside routers that are trying to perfect this.