Cómo deshabilitar enlaces HTML

Resuelto Ankit asked hace 12 años • 16 respuestas

Tengo un botón de enlace dentro <td>que tengo que desactivar. Esto funciona en IE pero no en Firefox y Chrome.

Intenté todo lo siguiente pero no funcionó en Firefox (usando 1.4.2 js):

$(".myLink").attr('disabled', 'disabled');

$(".myLink").attr('disabled', true);

$(".myLink").attr('disabled', 'true');

Nota: No puedo cancelar el registro de la función de clic para la etiqueta de anclaje ya que está registrada dinámicamente. Y TENGO QUE MOSTRAR EL ENLACE EN MODO DESHABILITADO.

Ankit avatar Apr 23 '12 14:04 Ankit
Aceptado

No puedes desactivar un enlace (de forma portátil). Puedes utilizar una de estas técnicas (cada una con sus propios beneficios y desventajas).

Manera CSS

Esta debería ser la forma correcta (pero verá más adelante) de hacerlo cuando la mayoría de los navegadores lo admitan:

a.disabled {
    pointer-events: none;
}

Es lo que hace, por ejemplo, Bootstrap 3.x. Actualmente (2016) solo es compatible con Chrome, Firefox y Opera (19+). Internet Explorer comenzó a admitir esto desde la versión 11, pero no para enlaces ; sin embargo, está disponible en un elemento externo como:

span.disable-links {
    pointer-events: none;
}

Con:

<span class="disable-links"><a href="#">...</a></span>

Solución alterna

Probablemente necesitemos definir una clase CSS, pointer-events: nonepero ¿qué pasa si reutilizamos el disabledatributo en lugar de una clase CSS? Estrictamente hablando, disabledno es compatible, <a>pero los navegadores no se quejarán de atributos desconocidos . El uso del disabledatributo IE lo ignorará pointer-eventspero respetará el disabledatributo específico de IE; otros navegadores compatibles con CSS ignorarán los atributos desconocidos disabled y los respetarán pointer-events. Es más fácil escribir que explicar:

a[disabled] {
    pointer-events: none;
}

Otra opción para IE 11 es establecer displayelementos de enlace a blocko inline-block:

<a style="pointer-events: none; display: inline-block;" href="#">...</a>

Tenga en cuenta que esta puede ser una solución portátil si necesita admitir IE (y puede cambiar su HTML) pero...

Dicho todo esto, tenga en cuenta que pointer-eventssolo desactiva... eventos de puntero. Los enlaces seguirán siendo navegables a través del teclado, entonces también deberá aplicar una de las otras técnicas que se describen aquí.

Enfocar

Junto con la técnica CSS descrita anteriormente, puede utilizarla tabindexde forma no estándar para evitar que un elemento se centre en:

<a href="#" disabled tabindex="-1">...</a>

Nunca verifiqué su compatibilidad con muchos navegadores, entonces quizás quieras probarlo tú mismo antes de usarlo. Tiene la ventaja de funcionar sin JavaScript. Desafortunadamente (pero obviamente) tabindexno se puede cambiar desde CSS.

Interceptar clics

Utilice a hrefpara una función de JavaScript, verifique la condición (o el atributo deshabilitado en sí) y no haga nada por si acaso.

$("td > a").on("click", function(event){
    if ($(this).is("[disabled]")) {
        event.preventDefault();
    }
});

Para deshabilitar enlaces haga esto:

$("td > a").attr("disabled", "disabled");

Para volver a habilitarlos:

$("td > a").removeAttr("disabled");

Si lo desea, .is("[disabled]")puede usarlo en lugar de .attr("disabled") != undefined(jQuery 1.6+ siempre regresará undefinedcuando el atributo no esté configurado) pero is()es mucho más claro (gracias a Dave Stewart por este consejo). Tenga en cuenta que aquí estoy usando el disabledatributo de una manera no estándar; si esto le interesa, reemplace el atributo con una clase y reemplácelo .is("[disabled]")con .hasClass("disabled")(agregando y eliminando con addClass()y removeClass()).

Zoltán Tamási señaló en un comentario que "en algunos casos, el evento de clic ya está vinculado a alguna función" real "(por ejemplo, usando knockoutjs). En ese caso, el orden del controlador de eventos puede causar algunos problemas. Por lo tanto, implementé enlaces deshabilitados vinculando un retorno controlador falso para los eventos touchstarty del enlace. Tiene algunos inconvenientes (evitará que se inicie el desplazamiento táctil en el enlace), mousedownperokeydown el manejo de eventos del teclado también tiene la ventaja de evitar la navegación con el teclado.

Tenga en cuenta que si hrefno se borra, es posible que el usuario visite esa página manualmente.

Limpiar el enlace

Borre el hrefatributo. Con este código no agregas un controlador de eventos pero cambias el enlace en sí. Utilice este código para desactivar enlaces:

$("td > a").each(function() {
    this.data("href", this.attr("href"))
        .attr("href", "javascript:void(0)")
        .attr("disabled", "disabled");
});

Y este para volver a habilitarlos:

$("td > a").each(function() {
    this.attr("href", this.data("href")).removeAttr("disabled");
});

Personalmente no me gusta mucho esta solución (si no tienes que hacer más con enlaces deshabilitados) pero puede ser más compatible debido a las varias formas de seguir un enlace.

Controlador de clics falsos

Agregue o elimine una onclickfunción en la que return falseno se seguirá su enlace. Para desactivar enlaces:

$("td > a").attr("disabled", "disabled").on("click", function() {
    return false; 
});

Para volver a habilitarlos:

$("td > a").removeAttr("disabled").off("click");

No creo que haya motivo para preferir esta solución a la primera.

Estilo

El estilo es aún más simple, sea cual sea la solución que estés usando para deshabilitar el enlace, agregamos un disabledatributo para que puedas usar la siguiente regla CSS:

a[disabled] {
    color: gray;
}

Si estás usando una clase en lugar de un atributo:

a.disabled {
    color: gray;
}

Si está utilizando un marco de interfaz de usuario, es posible que vea que los enlaces deshabilitados no tienen el estilo adecuado. Bootstrap 3.x, por ejemplo, maneja este escenario y el botón tiene el estilo correcto tanto con disabledatributo como con .disabledclase. Si, en cambio, estás borrando el enlace (o usando una de las otras técnicas de JavaScript), también debes manejar el estilo porque un <a>sin hreftodavía está pintado como habilitado.

Aplicaciones enriquecidas de Internet accesibles (ARIA)

No olvide incluir también un atributo aria-disabled="true"junto con disabledatributo/clase.

Adriano Repetti avatar Apr 23 '2012 07:04 Adriano Repetti

Obtuve la solución en CSS.

td.disabledAnchor a{
       pointer-events: none !important;
       cursor: default;
       color:Gray;
}

El CSS anterior, cuando se aplica a la etiqueta de anclaje, deshabilitará el evento de clic.

Para más detalles consulte este enlace

Ankit avatar Apr 23 '2012 14:04 Ankit

Gracias a todos los que publicaron soluciones (especialmente @AdrianoRepetti), combiné múltiples enfoques para proporcionar una disabledfuncionalidad más avanzada (y funciona en todos los navegadores). El código se encuentra a continuación (tanto ES2015 como Coffeescript según sus preferencias).

Esto proporciona múltiples niveles de defensa para que los anclajes marcados como deshabilitados realmente se comporten como tales. Con este enfoque, obtienes un ancla que no puedes:

  • hacer clic
  • tabulador y presione regresar
  • al tabularlo se moverá el foco al siguiente elemento enfocable
  • sabe si el ancla se habilita posteriormente

Cómo

  1. Incluya este CSS, ya que es la primera línea de defensa. Esto supone que el selector que utiliza esa.disabled

    a.disabled {
      pointer-events: none;
      cursor: default;
    }
    
  2. A continuación, cree una instancia de esta clase cuando esté lista (con selector opcional):

      new AnchorDisabler()
    

Clase ES2015

npm install -S key.js

import {Key, Keycodes} from 'key.js'

export default class AnchorDisabler {
  constructor (config = { selector: 'a.disabled' }) {
    this.config = config
    $(this.config.selector)
      .click((ev) => this.onClick(ev))
      .keyup((ev) => this.onKeyup(ev))
      .focus((ev) => this.onFocus(ev))
  }

  isStillDisabled (ev) {
    //  since disabled can be a class or an attribute, and it can be dynamically removed, always recheck on a watched event
    let target = $(ev.target)
    if (target.hasClass('disabled') || target.prop('disabled') == 'disabled') {
      return true
    }
    else {
      return false
    }
  }

  onFocus (ev) {
    //  if an attempt is made to focus on a disabled element, just move it along to the next focusable one.
    if (!this.isStillDisabled(ev)) {
      return
    }

    let focusables = $(':focusable')
    if (!focusables) {
      return
    }

    let current = focusables.index(ev.target)
    let next = null
    if (focusables.eq(current + 1).length) {
      next = focusables.eq(current + 1)
    } else {
      next = focusables.eq(0)
    }

    if (next) {
      next.focus()
    }
  }

  onClick (ev) {
    // disabled could be dynamically removed
    if (!this.isStillDisabled(ev)) {
      return
    }

    ev.preventDefault()
    return false
  }

  onKeyup (ev) {
    // We are only interested in disabling Enter so get out fast
    if (Key.isNot(ev, Keycodes.ENTER)) {
      return
    }

    // disabled could be dynamically removed
    if (!this.isStillDisabled(ev)) {
      return
    }

    ev.preventDefault()
    return false
  }
}

Clase de café:

class AnchorDisabler
  constructor: (selector = 'a.disabled') ->
    $(selector).click(@onClick).keyup(@onKeyup).focus(@onFocus)

  isStillDisabled: (ev) =>
    ### since disabled can be a class or an attribute, and it can be dynamically removed, always recheck on a watched event ###
    target = $(ev.target)
    return true if target.hasClass('disabled')
    return true if target.attr('disabled') is 'disabled'
    return false

  onFocus: (ev) =>
    ### if an attempt is made to focus on a disabled element, just move it along to the next focusable one. ###
    return unless @isStillDisabled(ev)

    focusables = $(':focusable')
    return unless focusables

    current = focusables.index(ev.target)
    next = (if focusables.eq(current + 1).length then focusables.eq(current + 1) else focusables.eq(0))

    next.focus() if next


  onClick: (ev) =>
    # disabled could be dynamically removed
    return unless @isStillDisabled(ev)

    ev.preventDefault()
    return false

  onKeyup: (ev) =>

    # 13 is the js key code for Enter, we are only interested in disabling that so get out fast
    code = ev.keyCode or ev.which
    return unless code is 13

    # disabled could be dynamically removed
    return unless @isStillDisabled(ev)

    ev.preventDefault()
    return false
kross avatar Oct 16 '2014 20:10 kross

Prueba el elemento:

$(td).find('a').attr('disabled', 'disabled');

Deshabilitar un enlace me funciona en Chrome: http://jsfiddle.net/KeesCBakker/LGYpz/ .

Firefox no parece funcionar bien. Este ejemplo funciona:

<a id="a1" href="http://www.google.com">Google 1</a>
<a id="a2" href="http://www.google.com">Google 2</a>

$('#a1').attr('disabled', 'disabled');

$(document).on('click', 'a', function(e) {
    if ($(this).attr('disabled') == 'disabled') {
        e.preventDefault();
    }
});

Nota: se agregó una declaración "en vivo" para futuros enlaces habilitados o deshabilitados.
Nota 2: se cambió "en vivo" a "activado".

Kees C. Bakker avatar Apr 23 '2012 07:04 Kees C. Bakker