¿Cómo simulo un mouseover en JavaScript puro que activa el CSS ": hover"?

82

He estado tratando de encontrar código para simular mouseoveren Chrome, pero aunque el oyente "mouseover" se activa, la declaración CSS "hover" nunca se establece.

Intenté también hacer:

//Called within mouseover listener
theElement.classList.add("hover");

Pero nada parece cambiar el elemento a lo que se declara en su hoverdeclaración.

es posible?

Don Rhummy
fuente
6
@PSL Creo que lo que quiere hacer es forzar el :hoverestado de un elemento.
Benjamin Gruenbaum
1
@BenjaminGruenbaum Sí, tienes razón. Entendí mal.
PSL
1
Esto no es un duplicado. La otra pregunta es sobre jQuery. Esta pregunta es sobre JS puro.
Chuck Le Butt
1
@Monk The OQ incluyó la etiqueta jQuery. Este es un duplicado.
JasonMArcher
1
@JasonMArcher La pregunta (y su respuesta) es sobre JS puro. ¿No crees que es más probable que lo hayan confundido?
Chuck Le Butt

Respuestas:

106

No puedes. No es un evento confiable .

Los eventos generados por el agente de usuario, ya sea como resultado de la interacción del usuario o como resultado directo de cambios en el DOM, son confiables por el agente de usuario con privilegios que no se otorgan a los eventos generados por el script a través de DocumentEvent.createEvent. ("Event"), modificado con el método Event.initEvent () o enviado mediante el método EventTarget.dispatchEvent (). El atributo isTrusted de los eventos confiables tiene un valor de verdadero, mientras que los eventos no confiables tienen un valor de atributo isTrusted de falso.

La mayoría de los eventos que no son de confianza no deberían activar acciones predeterminadas , con la excepción de los eventos de clic o DOMActivate.

Tienes que agregar una clase y agregar / eliminar eso en los eventos de mouseover / mouseout manualmente.

Benjamin Gruenbaum
fuente
4
@Tim, en realidad no responde por qué . Simplemente cambia la pregunta .
Pacerier
7
@Pacerier no es un evento confiable porque no fue iniciado por el usuario. Lo dice allí mismo en la cita anterior en mi respuesta. Es literalmente con lo que comienza la respuesta.
Benjamin Gruenbaum
1
@BenjaminGruenbaum, estoy citando "con la excepción de los eventos click o DOMActivate" . ¿Qué tiene de especial "hover" que no esté en esta lista de excepciones? ¿Por qué se nos permite llamar "foco" pero no "flotar"? Estas son las preguntas que tenemos que responder, responder cualquier otra cosa es simplemente cambiar la pregunta .
Pacerier
1
Asumiría que pasar el mouse (y combinado con hacer clic o el mouse hacia arriba y hacia abajo para arrastrar y soltar), podría comportarse o aparecer como secuestrar el sistema de un usuario (si ignora los casos de automatización), por lo que no es ideal para admitir. Haga clic en No puedo decir, pero el enfoque permitiría el enfoque automático a un campo de formulario de destino o elemento en el que el diseñador del sitio quiere que el usuario se enfoque, por ejemplo, un campo de texto con datos faltantes o incorrectos (por ejemplo, comprobaciones de validación de campo de formulario). Pero esas son solo mis suposiciones.
David
2
Sí, por absurdo que parezca, puede hacer que parezca que el enfoque fue causado por una interacción del usuario donde no lo fue. En la práctica, las API del navegador con mucho gusto desobedecerán la especificación e ignorarán el enfoque y harán clic como eventos no confiables (al menos Chrome). Intente, por ejemplo, simular un clic en el botón de instalación de una extensión para una extensión de Chrome y vea qué sucede :)
Benjamin Gruenbaum
37

Puede simular el evento de mouseover como este:

HTML

<div id="name">My Name</div>

JavaScript

var element = document.getElementById('name');
element.addEventListener('mouseover', function() {
  console.log('Event triggered');
});

var event = new MouseEvent('mouseover', {
  'view': window,
  'bubbles': true,
  'cancelable': true
});

element.dispatchEvent(event);
lbppers
fuente
Gracias, ¡todo lo que necesitaba eran burbujas! Haga clic con el botón derecho en un elemento del Inspector de la consola del desarrollador y haga "Usar en la consola" (Firefox) o "Almacenar como variable global" (Chrome). Entonces puede, por ejemplo, temp0.dispatchEvent(new MouseEvent('mouseover', {bubbles: true})) Muy útil para diseñar información sobre herramientas u otro contenido que solo aparece al pasar el mouse.
Denis Howe
Esto es fantástico.
rebelde
1
@DenisHowe Para ese caso de uso, debería revisar el :hovbotón en la parte superior del inspector de estilo en devtools. Le permite activar cualquier pseudoclase que desee en el elemento que se está inspeccionando.
Hallo
17

Antecedentes

Me encontré con esta pregunta mientras intentaba escribir pruebas automatizadas, para verificar que un cierto conjunto de elementos en una página determinada todos reciban algún conjunto de propiedades css establecidas por css para eventos de desplazamiento.

Si bien la respuesta anterior explica perfectamente por qué no es posible simplemente activar el evento de desplazamiento por JS y luego probar algún valor css de interés, responde la pregunta inicial "¿Cómo simulo un mouseover en JavaScript puro que activa el CSS" :flotar"?" sólo en parte.

Descargo de responsabilidad

Esta no es una solución eficaz. Lo usamos solo para pruebas automatizadas, donde el rendimiento no es una preocupación.

Solución

simulateCssEvent = function(type){
    var id = 'simulatedStyle';

    var generateEvent = function(selector){
        var style = "";
        for (var i in document.styleSheets) {
            var rules = document.styleSheets[i].cssRules;
            for (var r in rules) {
                if(rules[r].cssText && rules[r].selectorText){
                    if(rules[r].selectorText.indexOf(selector) > -1){
                        var regex = new RegExp(selector,"g")
                        var text = rules[r].cssText.replace(regex,"");
                        style += text+"\n";
                    }
                }
            }
        }
        $("head").append("<style id="+id+">"+style+"</style>");
    };

    var stopEvent = function(){
        $("#"+id).remove();
    };

    switch(type) {
        case "hover":
            return generateEvent(":hover");
        case "stop":
            return stopEvent();
    }
}

Explicación

generateEvent lee todos los archivos css, reemplaza: hover con una cadena vacía y lo aplica. Esto tiene el efecto de que se aplican todos los estilos: hover. Ahora se puede probar un estilo aullado y volver al estado inicial deteniendo la simulación.

¿Por qué aplicamos el efecto de desplazamiento para todo el documento y no solo para el elemento de interés obteniendo el de las hojas y luego realizamos un element.css (...)?

Hecho así, el estilo se aplicaría en línea, esto anularía otros estilos, que podrían no ser anulados por el estilo de desplazamiento css original.

¿Cómo simularía ahora el desplazamiento para un solo elemento?

Esto no funciona, así que mejor no lo haga. Si debe hacerlo, puede verificar con element.is (selectorOfInterest) si el estilo se aplica a su elemento y solo usar esos estilos.

Ejemplo

En Jasmine puedes, por ejemplo, realizar ahora:

describe("Simulate CSS Event", function() {
    it("Simulate Link Hover", function () {
      expect($("a").css("text-decoration")).toBe("none");
      simulateCssEvent('hover');
      expect($("a").css("text-decoration")).toBe("underline");
      simulateCssEvent('stop');
      expect($("a").css("text-decoration")).toBe("none");
    });
});
Amstutz
fuente
1
¡Esta respuesta es genial! Desafortunadamente, falla en las versiones recientes de Chrome en páginas con hojas de estilo servidas desde otros hosts debido a que Chrome limita el acceso a solicitudes de origen cruzado. Vea mi respuesta para una solución que admita esto :)
FThompson
6

Lo que suelo hacer en este caso es agregar una clase usando javascript ... y adjuntar lo mismo CSSque :hovera esta clase

Intenta usar

theElement.addEventListener('onmouseover', 
    function(){ theElement.className += ' hovered' });

O para navegadores más antiguos:

theElement.onmouseover = function(){theElement.className += ' hovered'};

por supuesto, tendrá que usar onmouseoutpara eliminar la clase "flotante" cuando deje el elemento ...

Yotam Omer
fuente
Esto no hará lo que pide el OP, aunque probablemente sea más o menos en la línea correcta. Sería mejor utilizar técnicas modernas de conexión de controladores de eventos.
Puntiagudo
lo siento, pregunta mal entendida
Yotam Omer
@Pointy la pregunta pide javascript puro ... ¿cómo se pueden adjuntar los eventos de otra manera?
Yotam Omer
2
¿No es suficiente? Es JavaScript "puro" y, de hecho, adjuntará una función como controlador para un evento. En Internet Explorer, attachEvent()se usaría el (casi) equivalente .
Puntiagudo
Vale la pena mencionar. Compatible con IE9 y 10 addEventListenery es la mejor manera de adjuntar eventos, el shimming attachEventsolo es necesario en IE8 (y más abajo). Yotam, si agrega otro controlador aonmouseover estableciendo el atributo directamente (en lugar de agregar el detector de eventos), anulará el evento configurado actualmente. Vea esta pregunta sobre la diferencia.
Benjamin Gruenbaum
4

Puede usar pseudo: styler , una biblioteca que puede aplicar pseudoclases CSS a elementos.

(async () => {
  let styler = new PseudoStyler();
  await styler.loadDocumentStyles();
  document.getElementById('button').addEventListener('click', () => {
    const element = document.getElementById('test')
    styler.toggleStyle(element, ':hover');
  })
})();

Descargo de responsabilidad: soy coautor de esta biblioteca. Lo diseñamos para admitir adicionalmente hojas de estilo de origen cruzado, específicamente para su uso en extensiones de Chrome donde es probable que no tenga control sobre las reglas CSS de la página.

FThompson
fuente
1
Esto parece funcionar bastante bien, incluso cuando se combina con window.getComputedStyle(<youElement>)después de establecer el pseudo estilo. ¡Gracias!
Daniel Veihelmann
2

Supongo que desea inspeccionar el CSS después de la manipulación de dom, pero tan pronto como mueva el mouse de regreso a devtools, el evento ya no está activo en ese elemento html. Probablemente le gustaría tener algo como la opción: hover en devtools para sus eventos javascript. Eso no existe, pero puedes simularlo.

  1. Abra sus devtools y haga clic en él para activarlo.
  2. Activa el evento en el elemento que te interesa.
  3. Sin mover el mouse, abra el panel de comandos de devtools con ctrl + shift + py seleccione 'deshabilitar javascript' con su teclado.

Dado que JavaScript está deshabilitado, no tiene la oportunidad de volver a modificar los elementos. Puede ir a devtools e inspeccionar css y html como si estuviera flotando, haciendo clic o haciendo otra cosa con él. Una vez que haya terminado, vaya al panel de comandos nuevamente y seleccione 'habilitar javascript'.

Piepongwong
fuente
Delicada técnica, pero a menos que no he entendido bien su intención, este no existe ya en devtools! En las herramientas de desarrollo de Chrome / Chromium y Firefox, hay un :hovbotón en la parte superior del inspector de estilo (junto al cuadro de entrada "Filtro"). Al hacer clic :hovse expande una serie de casillas de verificación, cada uno marcado con un pseudoclass: :active, :focus, :focus-within, :hover, y :visited. Y al marcar cualquiera de estas casillas, se activa su respectiva pseudoclase en el elemento que se está inspeccionando.
Hallo