Jak zasymulować najechanie kursorem myszy w czystym JavaScript, który aktywuje „: hover” w CSS?

83

Próbowałem znaleźć kod do symulacji mouseoverw Chrome, ale mimo że detektor „najechania myszą” zostaje uruchomiony, deklaracja CSS „najechanie kursorem” nigdy nie jest ustawiona!

Próbowałem też zrobić:

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

Ale wydaje się, że nic nie zmienia elementu na to, co jest zadeklarowane w jego hoverdeklaracji.

czy to możliwe?

Don Rhummy
źródło
6
@PSL Myślę, że on chce wymusić :hoverstan na elemencie.
Benjamin Gruenbaum
1
@BenjaminGruenbaum Tak, masz rację. Źle zrozumiałem.
PSL
1
To nie jest duplikat. Drugie pytanie dotyczy jQuery. To pytanie dotyczy czystego JS.
Chuck Le Butt
1
@Monk OQ zawiera tag jQuery. To jest duplikat.
JasonMArcher
1
@JasonMArcher Pytanie (i odpowiedź) dotyczy czystego JS. Nie sądzisz, że bardziej prawdopodobne jest, że pomylili to.
Chuck Le Butt

Odpowiedzi:

106

Nie możesz. To nie jest zaufane wydarzenie .

Zdarzenia generowane przez agenta użytkownika, w wyniku interakcji użytkownika lub bezpośrednio w wyniku zmian w DOM, są zaufane przez agenta użytkownika z uprawnieniami, które nie są nadawane zdarzeniom generowanym przez skrypt za pośrednictwem DocumentEvent.createEvent („Event”), zmodyfikowanej za pomocą metody Event.initEvent () lub wysłanej za pomocą metody EventTarget.dispatchEvent (). Atrybut isTrusted zaufanych zdarzeń ma wartość true, podczas gdy niezaufane zdarzenia mają wartość false atrybutu isTrusted.

Większość niezaufanych zdarzeń nie powinna wywoływać domyślnych działań , z wyjątkiem kliknięć i zdarzeń DOMActivate.

Musisz dodać klasę i ręcznie dodać / usunąć ją przy zdarzeniach najechania myszą / myszy.

Benjamin Gruenbaum
źródło
4
@Tim, to właściwie nie odpowiada dlaczego . To tylko zmienia pytanie .
Pacerier
7
@Pacerier to nie jest zaufane zdarzenie, ponieważ nie zostało zainicjowane przez użytkownika. Mówi więc tam w cytacie powyżej w mojej odpowiedzi. Dosłownie od tego zaczyna się odpowiedź.
Benjamin Gruenbaum
1
@BenjaminGruenbaum, cytuję „z wyjątkiem zdarzeń click lub DOMActivate” . Co jest takiego specjalnego w „najeździe”, że nie ma go na tej liście wyjątków? Dlaczego możemy nazywać „focus”, ale nie „hover”? Oto pytania, na które musimy odpowiedzieć, odpowiadanie na cokolwiek innego to po prostu zmiana pytania .
Pacerier
1
Zakładam, że najechanie kursorem (w połączeniu z kliknięciem lub przyciskiem myszy w górę i w dół do przeciągania i upuszczania) może zachowywać się lub wyglądać jak przejęcie systemu użytkownika (jeśli zignorujesz przypadki automatyzacji), więc nie jest to idealne rozwiązanie do obsługi. Kliknij Nie mogę powiedzieć, ale fokus pozwoliłby na automatyczne skupienie się na docelowym polu formularza lub elemencie, na którym projektant witryny chce, aby użytkownik skupił się, na przykład pole tekstowe z brakującymi lub niepoprawnymi danymi (np. Sprawdzanie poprawności pól formularza). Ale to tylko moje przypuszczenia.
David
2
Tak, choć brzmi to absurdalnie, możesz sprawić, że zacznie się wydawać, że skupienie zostało spowodowane interakcją użytkownika, podczas gdy jej nie było. W praktyce - interfejsy API przeglądarek chętnie nie zastosują się do specyfikacji i zignorują fokus i kliknięcie jako niezaufane zdarzenia (przynajmniej Chrome). Spróbuj na przykład symulację kliknij na przycisk zainstalować rozszerzenie o rozszerzenie Chrome i zobaczyć co się dzieje :)
Benjamin Gruenbaum
39

Możesz zasymulować zdarzenie najechania myszą w następujący sposób:

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);
lbpeppers
źródło
Dzięki, potrzebowałem tylko bąbelków! Kliknij prawym przyciskiem myszy element w Inspektorze konsoli programisty i wykonaj „Użyj w konsoli” (Firefox) lub „Zapisz jako zmienną globalną” (Chrome). Wtedy możesz np. temp0.dispatchEvent(new MouseEvent('mouseover', {bubbles: true})) Bardzo przydatne do stylizowania podpowiedzi lub innych treści, które pojawiają się tylko po najechaniu myszą.
Denis Howe
To jest fantastyczne.
buntownik
1
@DenisHowe W tym przypadku powinieneś sprawdzić :hovprzycisk u góry inspektora stylów w devtools. Pozwala aktywować dowolną pseudoklasę na kontrolowanym elemencie.
witaj
17

tło

Natknąłem się na to pytanie, próbując napisać testy automatyczne, aby sprawdzić, czy określony zestaw elementów na danej stronie, które wszystkie otrzymują, ma pewien zestaw właściwości css ustawionych przez css dla zdarzeń po najechaniu.

Chociaż powyższa odpowiedź doskonale wyjaśnia, dlaczego nie można po prostu wywołać zdarzenia najechania kursorem przez JS, a następnie sondować jakąś interesującą wartość css, odpowiada ona na wstępne pytanie „Jak zasymulować najechanie kursorem myszy w czystym JavaScript, który aktywuje CSS” :unosić się"?" tylko częściowo.

Zrzeczenie się

To nie jest wydajne rozwiązanie. Używamy go tylko do testów automatycznych, gdzie wydajność nie jest problemem.

Rozwiązanie

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();
    }
}

Wyjaśnienie

geneEvent odczytuje wszystkie pliki css,, zastępuje: hover pustym ciągiem znaków i stosuje go. W efekcie stosowane są style all: hover. Teraz można zbadać styl howered i wrócić do stanu początkowego, zatrzymując symulację.

Dlaczego stosujemy efekt najechania na cały dokument, a nie tylko na interesujący nas element, pobierając z arkuszy i wykonując element.css (...)?

W ten sposób styl zostałby zastosowany w tekście, co spowodowałoby zastąpienie innych stylów, które mogą nie zostać zastąpione przez oryginalny styl najechania css.

Jak mógłbym teraz zasymulować najechanie na pojedynczy element?

To nie jest wydajne, więc lepiej tego nie robić. Jeśli musisz, możesz sprawdzić za pomocą elementu element.is (selectorOfInterest), czy styl ma zastosowanie do twojego elementu i używać tylko tych stylów.

Przykład

W Jasmine możesz teraz np. Wykonać:

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
źródło
1
Ta odpowiedź jest świetna! Niestety, nie działa w najnowszych wersjach Chrome na stronach z arkuszami stylów obsługiwanymi przez inne hosty, ponieważ Chrome ogranicza dostęp do żądań z różnych źródeł. Zobacz moją odpowiedź na rozwiązanie, które to obsługuje :)
FThompson
6

To, co zwykle robię w tym przypadku, to dodanie klasy za pomocą javascript .. i dołączenie tego samego CSSco :hoverdo tej klasy

Spróbuj użyć

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

Lub w przypadku starszych przeglądarek:

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

będziesz oczywiście musiał użyć, onmouseoutaby usunąć klasę „najechaną” po opuszczeniu elementu ...

Yotam Omer
źródło
To nie zrobi tego, o co prosi PO, chociaż prawdopodobnie jest mniej więcej zgodne z prawdą. Lepiej byłoby użyć nowoczesnych technik dołączania obsługi zdarzeń.
Pointy
przepraszam, niezrozumiane pytanie
Yotam Omer
@Pointy pytanie dotyczy czystego javascript .. jak inaczej można dołączyć zdarzenia?
Yotam Omer
2
Nie wystarczająco dobre? Jest to „czysty” JavaScript i w rzeczywistości dołącza funkcję jako moduł obsługi zdarzenia. W przeglądarce Internet Explorer attachEvent()zostanie użyty (prawie) odpowiednik .
Pointy,
Warte wspomnienia. Obsługa IE9 i 10 addEventListeneri jest to najlepszy sposób na dołączanie zdarzeń, shimming attachEventjest potrzebny tylko w IE8 (i niższych). Yotam, jeśli doda kolejną procedurę obsługi onmouseoverprzez bezpośrednie ustawienie atrybutu (zamiast dodawania detektora zdarzeń), nadpisuje aktualnie ustawione zdarzenie. Zobacz to pytanie na temat różnicy.
Benjamin Gruenbaum
4

Możesz użyć pseudo: styler , biblioteki, która może nakładać pseudoklasy CSS na elementy.

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

Zastrzeżenie: jestem współautorem tej biblioteki. Zaprojektowaliśmy go tak, aby dodatkowo obsługiwał arkusze stylów z różnych źródeł, szczególnie do użytku w rozszerzeniach Chrome, w których prawdopodobnie brakuje kontroli nad regułami CSS strony.

FThompson
źródło
1
Wydaje się, że działa to całkiem nieźle, nawet w połączeniu z window.getComputedStyle(<youElement>)po ustawieniu pseudo stylu. Dzięki!
Daniel Veihelmann
2

Zakładam, że chcesz sprawdzić CSS po manipulacji w domenie, ale gdy tylko przesuniesz mysz z powrotem do devtools, zdarzenie nie jest już aktywne dla tego elementu html. Prawdopodobnie chciałbyś mieć opcję: hover w devtools dla zdarzeń javascript. To nie istnieje, ale możesz to zasymulować.

  1. Otwórz devtools i kliknij je, aby uaktywnić.
  2. Wywołaj zdarzenie na elemencie, który Cię interesuje.
  3. Bez poruszania myszą otwórz panel poleceń devtools za pomocą ctrl + shift + p i wybierz opcję „wyłącz javascript” za pomocą klawiatury.

Ponieważ javascript jest wyłączony, nie ma szansy na ponowne zmodyfikowanie elementu (ów). Możesz przejść do devtools i sprawdzić css i html, tak jakbyś najechał kursorem, kliknął lub zrobił coś innego. Gdy skończysz, ponownie przejdź do panelu poleceń i wybierz opcję „włącz javascript”.

Piepongwong
źródło
Technika schludny, ale chyba źle swoją intencją, to nie istnieją już w DevTools! W obu narzędziach devtools Chrome / Chromium i Firefox, :hovu góry inspektora stylów (obok pola wprowadzania „Filtr”) znajduje się przycisk. Kliknięcie :hovrozszerza serię wyboru, każdy znakowany pseudoclass: :active, :focus, :focus-within, :hover, i :visited. Zaznaczenie któregokolwiek z tych pól aktywuje odpowiednią pseudoklasę na kontrolowanym elemencie.
cześć