Header Ads Widget

Ticker

6/recent/ticker-posts

JavaScript: Abrir enlace en una nueva pestaña

Los principales navegadores tienen bloqueadores de ventanas emergentes que a veces impiden que los sitios abran nuevas pestañas. Este artículo investiga cómo funcionan actualmente los bloqueadores de ventanas emergentes, qué bloquean y cómo superar los problemas que causan.

El primer capítulo ofrece una breve descripción de los bloqueadores de ventanas emergentes. El resto del artículo muestra varias formas de abrir una nueva pestaña y cómo evitar las limitaciones de los navegadores.

Bloqueadores de ventanas emergentes

Para el navegador, no hay diferencia entre nueva pestaña y ventana emergente. Los bloqueadores de ventanas emergentes los tratan de la misma manera. Por lo tanto, este artículo usa "nueva pestaña" y "nueva ventana" indistintamente.

El bloqueador de ventanas emergentes integrado dentro de Firefox está dispuesto a abrir una nueva pestaña solo desde el administrador de un clic. Evita la apertura de pestañas desde el evento del mouse sobre el evento, la respuesta a la solicitud de la red y desde el script interno en el cuerpo. En lugar de abrir una nueva pestaña, Firefox mostrará un banner de advertencia amarillo que dice  Firefox prevented this site from opening popupEs posible desactivar la advertencia, pero eso requiere la acción del usuario.

Edge funciona de manera similar a Firefox, excepto que el banner es blanco y se muestra en la parte inferior de la ventana.

Chrome siempre evita que las pestañas nuevas respondan a las solicitudes de red. En su mayoría, evita que también aparezcan nuevas pestañas en el evento y el script dentro del cuerpo. Los dos últimos se crean a veces, pero no encontré cuándo exactamente. Chrome muestra un pequeño icono en la barra de URL cuando se niega a abrir la nueva pestaña. El usuario puede hacer clic en él y permitir ventanas emergentes manualmente.

Enlace HTML

La forma más sencilla de crear un enlace que se abre en una nueva pestaña es agregarlo  target="_blank" . Funciona en Chrome, Firefox y Edge.

1
<a href="http://gooogle.com" target="_blank">Normal Link</a>

Así es como se renderiza:  Enlace normal

JavaScript

JavaScript puede abrir una nueva pestaña usando la  window.open(URL, name, specs, replace) función. El truco consiste  '_blank' en  name argumentar.

1
window.open('https://www.google.com', '_blank');

Esto funciona en la mayoría de las situaciones, pero no en todas. Lo más importante es que Edge y Firefox bloquean la nueva pestaña del controlador de respuesta de solicitud de red. Cuando la URL debe cargarse desde el backend, Firefox requiere trucos para funcionar.

Este capítulo tiene dos secciones. La primera sección  trata sobre la situación en la que la interfaz conoce la URL. La segunda sección  muestra cómo abrir el enlace en una nueva pestaña cuando el frente necesita enviar una solicitud de red.

Cuando se conoce la URL

En este capítulo, intentaremos abrir una nueva pestaña desde el clic del mouse, desde el temporizador, desde el mouse y desde un script dentro del cuerpo.

Desde clic

Abrir una nueva pestaña desde el  onclick atributo de la etiqueta html funciona desde Chrome, Firefox y Edge:

1
2
3
4
<a href="#" onclick="<font></font>
    window.open('https://www.google.com', '_blank');<font></font>
    return false;<font></font>
">on click</a><font></font>

Así es como se renderiza:  al hacer clic

Desde Timer Inside Click

También puede iniciar un temporizador mientras maneja el método onclick de los usuarios y abrir una nueva pestaña más tarde desde el temporizador. Funciona en Chrome, Firefox y Edge:

1
2
3
4
<a href="#" onclick="<font></font>
    setTimeout(() => window.open('https://www.google.com', '_blank'), 500);<font></font>
    return false;<font></font>
">click starts timer</a><font></font>

Así es como se renderiza: el  clic inicia el temporizador

Desde el mouse sobre

Abrir una nueva pestaña desde el  onmouseover atributo de una etiqueta html no funciona. Firefox y Edge lo bloquean todo el tiempo. Chrome lo bloquea la mayor parte del tiempo, aunque el bloqueo no es perfecto y la pestaña aparece ocasionalmente:

1
2
3
4
<a href="#" onmouseover="<font></font>
    window.open('https://www.google.com', '_blank');<font></font>
    return false;<font></font>
">on mouse over</a><font></font>

Así es como se renderiza:  al pasar el mouse sobre

Desde el temporizador dentro del mouse sobre

Abrir nueva pestaña desde el temporizador iniciado en el interior  onmouseover no funciona. Firefox y Edge lo bloquean todo el tiempo. Chrome lo bloquea la mayor parte del tiempo, aunque el bloqueo no es perfecto y la pestaña aparece de vez en cuando:

1
2
3
4
5
6
<a href="#" onmouseover="<font></font>
setTimeout(function() {<font></font>
 window.open('https://www.google.com', '_blank');<font></font>
} ,500);<font></font>
return false;<font></font>
">timer on mouseover</a></br><font></font>

Así es como se renderiza: temporizador al pasar  el mouse

De Body Onload

Los tres navegadores bloquean la apertura de una nueva pestaña desde el script en el cuerpo. Agrega esto dentro de la etiqueta del cuerpo para verlo:

1
2
3
4
5
6
7
<script><font></font>
 console.log("installing");<font></font>
 setTimeout(function() {<font></font>
  console.log("running");<font></font>
  window.open('https://www.google.com', '_blank');<font></font>
 }, 500);<font></font>
</script><font></font>
Obteniendo URL del backend

Un caso más interesante y útil es cuando la aplicación web necesita obtener la URL del backend. La solución sencilla no funciona, Edge y Firefox bloquean la nueva pestaña. Sin embargo, este caso de uso es demasiado útil para ignorarlo, por lo que crearemos una solución alternativa.

De solicitud de respuesta

La apertura de una nueva pestaña desde la respuesta a la solicitud solo funciona en Chrome. Edge y Firefox muestran una advertencia amarilla y evitan que se abra una nueva pestaña:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
dieciséis
17
<script><font></font>
function fromHttpRequest() {<font></font>
 const Http = new XMLHttpRequest();<font></font>
 const url='https://jsonplaceholder.typicode.com/posts';<font></font>
 Http.open("GET", url);<font></font>
 Http.send();<font></font>
 <font></font>
 Http.onreadystatechange = (e) => {<font></font>
   console.log(Http.responseText)<font></font>
   window.open('https://www.google.com', '_blank');<font></font>
 }<font></font>
}<font></font>
</script><font></font>
<a href="#" onclick="<font></font>
    fromHttpRequest();<font></font>
    return false;<font></font>
">from http request</a></br><font></font>

Así es como se renderiza:  desde la solicitud http

Iniciar el temporizador desde la respuesta a la solicitud no ayuda. Chrome y Edge abrirán la pestaña, pero Firefox mostrará una advertencia en su lugar. He omitido el ejemplo porque es largo y casi igual que los temporizadores anteriores.

Solución 1

La solución es combinar el intervalo de JavaScript iniciado desde el clic del usuario, la solicitud de red y dejar que se comunique a través de la variable.

  • La solicitud de red espera una respuesta. Luego establece la variable común.
  • El intervalo comprueba periódicamente el valor de la variable. Abre una nueva pestaña una vez que la variable tiene la respuesta. Entonces el intervalo se quita solo.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
dieciséis
17
18
19
20
21
22
23
24
25
26
27
28
29
<script><font></font>
function intervalListensForRequestResponse() {<font></font>
 var iHaveTheResponse; // shared variable<font></font>
 <font></font>
 // send request<font></font>
 const Http = new XMLHttpRequest();<font></font>
 const url='https://jsonplaceholder.typicode.com/posts';<font></font>
 Http.open("GET", url);<font></font>
 Http.send();<font></font>
 <font></font>
 Http.onreadystatechange = (e) => {<font></font>
   console.log(Http.responseText)<font></font>
   iHaveTheResponse = 'https://www.google.com';<font></font>
 }<font></font>
 <font></font>
 // periodically check the variable<font></font>
 var refreshIntervalId = setInterval(function(){<font></font>
    console.log('tick ' + iHaveTheResponse);<font></font>
    if (iHaveTheResponse) {<font></font>
     window.open(iHaveTheResponse, '_blank')<font></font>
     clearInterval(refreshIntervalId);<font></font>
    }<font></font>
  }, 500);<font></font>
 return false;<font></font>
}<font></font>
</script><font></font>
<a  href="#" onclick="<font></font>
    return intervalListensForRequestResponse();<font></font>
">interval listens for request response</a><font></font>

Así es como se representa: el  intervalo escucha la respuesta de la solicitud

Solución 2

Si el frontend sabe con certeza que tendrá que abrir una nueva pestaña y solo necesita adquirir la URL correcta del backend, puede:

  1. Abre una nueva ventana y mantén la referencia a ella.
  2. Envíe la solicitud.
  3. Establezca la URL en la ventana recién abierta.

La desventaja de esta solución es que se abre una nueva ventana antes de que regrese la respuesta del backend. Hay una ventana en blanco durante unos milisegundos. Además, es imposible hacer que el backend decida si la ventana será necesaria o no.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
dieciséis
17
18
19
20
21
22
23
24
<script><font></font>
function startByOpeningTheWindow() {<font></font>
 var newTab = window.open("", '_blank');<font></font>
 if (newTab==null) {<font></font>
  return ;<font></font>
 }<font></font>
 <font></font>
 <font></font>
 // send request<font></font>
 const Http = new XMLHttpRequest();<font></font>
 const url='https://jsonplaceholder.typicode.com/posts';<font></font>
 Http.open("GET", url);<font></font>
 Http.send();<font></font>
 <font></font>
 Http.onreadystatechange = (e) => {<font></font>
   console.log(Http.responseText);<font></font>
   newTab.location.href = 'https://www.google.com';<font></font>
 }<font></font>
 return false;<font></font>
}<font></font>
</script><font></font>
<a href="#"<font></font>
      onclick="startByOpeningTheWindow();"<font></font>
>first open the window, change url later</a></br><font></font>

Así es como se representa:  primero abra la ventana, cambie la URL más tarde

Algunas notas sobre la función abierta

La comunicación entre la ventana original y la nueva pestaña es posible si tienen el mismo origen. Si muestran páginas de diferentes dominios, el navegador bloquea la comunicación debido a las reglas de la Política del mismo origen. Termina con un  Error: uncaught exception: Permission denied to get property error.

La  window.open función devuelve una referencia a la pestaña que se acaba de abrir. La página original puede usarla para llamar a funciones dentro de la pestaña recién abierta. Si el bloqueador de ventanas emergentes de Firefox bloqueó la ventana emergente, la función regresa  nullPuede usar esto para verificar si la nueva pestaña fue bloqueada. Este método solo funciona para el bloqueador de ventanas emergentes incorporado, no funciona para los complementos de bloqueo de anuncios.

La nueva pestaña tiene la  opener propiedad que se puede usar para llamar a funciones dentro de la ventana principal. También tiene la  closed propiedad. La ventana principal puede usarla para verificar si la pestaña secundaria estaba abierta o no.

Publicar un comentario

0 Comentarios