Как смоделировать наведение курсора на чистый JavaScript, который активирует CSS «: hover»?

83

Я пытался найти код для моделирования mouseoverв Chrome, но даже несмотря на то, что слушатель «mouseover» запускается, объявление CSS «hover» никогда не устанавливается!

Я также пробовал делать:

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

Но, похоже, ничто не меняет элемент на то, что объявлено в его hoverобъявлении.

Это возможно?

Дон Рамми
источник
6
@PSL Я думаю, что он хочет принудительно :hoverустановить состояние элемента.
Benjamin Gruenbaum
1
@BenjaminGruenbaum Ага, ты прав. Я неправильно понял.
PSL
1
Это не дубликат. Другой вопрос о jQuery. Это вопрос о чистом JS.
Чак Ле Батт
1
@Monk OQ включал тег jQuery. Это дубликат.
JasonMArcher
1
@JasonMArcher Вопрос (и ответ) о чистом JS. Вы не думаете, что они скорее ошиблись?
Чак Ле Батт

Ответы:

106

Вы не можете. Это не заслуживающее доверия событие .

Пользовательский агент доверяет событиям, которые генерируются пользовательским агентом либо в результате взаимодействия с пользователем, либо как прямой результат изменений в DOM, с привилегиями, которые не предоставляются событиям, генерируемым скриптом через DocumentEvent.createEvent. ("Событие"), измененный с помощью метода Event.initEvent () или отправленный с помощью метода EventTarget.dispatchEvent (). Атрибут isTrusted доверенных событий имеет значение true, а ненадежные события имеют значение атрибута isTrusted false.

Большинство ненадежных событий не должны запускать действия по умолчанию , за исключением событий click или DOMActivate.

Вам нужно добавить класс и добавить / удалить его в событиях mouseover / mouseout вручную.

Бенджамин Грюнбаум
источник
4
@ Тим, на самом деле он не отвечает, почему . Это просто меняет вопрос .
Pacerier
7
@Pacerier это ненадежное событие, потому что оно не было инициировано пользователем. Он говорит так прямо в цитате выше в моем ответе. Буквально с этого начинается ответ.
Бенджамин Грюнбаум
1
@BenjaminGruenbaum, я цитирую «за исключением событий click или DOMActivate» . Что такого особенного в "наведении", что его нет в этом списке исключений? Почему нам разрешено называть «фокус», но не «наведение»? Это те вопросы, на которые мы должны ответить. Если ответить на что-нибудь еще, это просто меняет вопрос .
Pacerier
1
Я бы предположил, что наведение (и в сочетании с щелчком или мышью вверх и вниз для перетаскивания) может вести себя или выглядеть как захват системы пользователя (если вы игнорируете случаи автоматизации), поэтому он не идеален для поддержки. Щелкните «Я не могу сказать», но фокус позволит автоматически сфокусироваться на целевом поле или элементе формы, на котором разработчик сайта хочет, чтобы пользователь сосредоточился, например, на текстовом поле с отсутствующими или неверными данными (например, проверками проверки поля формы). Но это только мои предположения.
Дэвид
2
Да, как бы абсурдно это ни звучало, вы можете создать впечатление, что фокус был вызван взаимодействием с пользователем, хотя его не было. На практике API-интерфейсы браузера с радостью не подчинятся спецификации и проигнорируют фокус и щелкнут как ненадежные события (по крайней мере, Chrome). Попробуйте, например, смоделировать щелчок по кнопке установки расширения для расширения Chrome и посмотрите, что произойдет :)
Бенджамин Грюнбаум
39

Вы можете смоделировать событие наведения указателя мыши следующим образом:

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);
andresscode
источник
Спасибо, все, что мне было нужно, это пузыри! Щелкните правой кнопкой мыши элемент в инспекторе консоли разработчика и выберите «Использовать в консоли» (Firefox) или «Сохранить как глобальную переменную» (Chrome). Тогда вы можете, например, temp0.dispatchEvent(new MouseEvent('mouseover', {bubbles: true})) очень полезно для стилизации всплывающих подсказок или другого контента, который появляется только при наведении курсора мыши.
Денис Хоу
Это фантастика.
rebelliard
1
@DenisHowe Для этого варианта использования вам следует проверить :hovкнопку в верхней части инспектора стилей в devtools. Он позволяет вам активировать любой псевдокласс на проверяемом элементе.
Привет,
17

Задний план

Я наткнулся на этот вопрос, пытаясь написать автоматические тесты, чтобы убедиться, что определенный набор элементов на данной странице, все получаемые, имеют некоторый набор свойств css, установленных css для событий при наведении курсора.

Хотя приведенный выше ответ прекрасно объясняет, почему невозможно просто вызвать событие зависания с помощью JS, а затем проверить какое-либо интересующее значение css, он отвечает на первоначальный вопрос «Как имитировать наведение курсора на чистый JavaScript, который активирует CSS». : hover »?" только частично.

Отказ от ответственности

Это неэффективное решение. Мы используем его только для автоматизированного тестирования, когда производительность не имеет значения.

Решение

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

Объяснение

generateEvent читает все файлы css, заменяет: hover пустой строкой и применяет ее. В результате применяются все стили: hover. Теперь можно проверить какой-либо стиль и вернуться в исходное состояние, остановив моделирование.

Почему мы применяем эффект наведения для всего документа, а не только для интересующего элемента, получая из листов и затем выполняя element.css (...)?

Таким образом, стиль будет применен встроенным, это переопределит другие стили, которые не могут быть переопределены исходным стилем наведения CSS.

Как бы я теперь смоделировал наведение для одного элемента?

Это неэффективно, так что лучше не надо. При необходимости вы можете проверить с помощью element.is (selectorOfInterest), применяется ли стиль к вашему элементу, и использовать только эти стили.

пример

В Jasmine вы можете, например, теперь выполнять:

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");
    });
});
Амштуц
источник
1
Отличный ответ! К сожалению, он не работает в последних версиях Chrome на страницах с таблицами стилей, обслуживаемыми с других хостов, из-за ограничения доступа Chrome к запросам из разных источников. См. Мой ответ о решении, которое поддерживает это :)
FThompson
6

Что я обычно делаю в этом случае, так это добавляю класс с помощью javascript .. и прикрепляю к этому классу то же самое, CSSчто и:hover

Попробуйте использовать

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

Или для старых браузеров:

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

вам, конечно, придется использовать, onmouseoutчтобы удалить "зависший" класс, когда вы покидаете элемент ...

Йотам Омер
источник
Это не будет делать то, что просит OP, хотя, вероятно, это более или менее в правильном направлении. Было бы лучше использовать современные методы присоединения обработчиков событий.
Pointy
извините, неправильно понятый вопрос
Йотам Омер
@Pointy вопрос требует чистого javascript .. как иначе можно прикрепить события?
Yotam Omer
2
Не достаточно хорошо? Это «чистый» JavaScript, и он фактически присоединяет функцию в качестве обработчика события. В Internet Explorer attachEvent()будет использоваться (почти) эквивалент .
Pointy
Стоит отметить. IE9 и 10 поддерживают, addEventListenerи это лучший способ прикреплять события, шиммирование attachEventтребуется только в IE8 (и ниже). Йотам, если он добавит другой обработчик onmouseover, установив атрибут напрямую (а не добавляя прослушиватель событий), он переопределит текущее установленное событие. Видеть Этот вопрос о разнице.
Benjamin Gruenbaum
4

Вы можете использовать pseudo: styler , библиотеку, которая может применять псевдоклассы CSS к элементам.

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

Отказ от ответственности: я являюсь соавтором этой библиотеки. Мы разработали его для дополнительной поддержки таблиц стилей разных источников, особенно для использования в расширениях Chrome, где вам, вероятно, не хватает контроля над правилами CSS страницы.

Ф.Томпсон
источник
1
Кажется, что это действительно работает довольно хорошо, даже в сочетании с window.getComputedStyle(<youElement>)после установки псевдостиля. Благодаря!
Даниэль Вейхельманн
2

Я предполагаю, что вы хотите проверить CSS после манипуляции с dom, но как только вы переместите указатель мыши обратно в инструменты разработчика, событие больше не будет активным для этого элемента html. Вы, вероятно, хотели бы иметь что-то вроде опции: hover в devtools для ваших событий javascript. Этого не существует, но вы можете смоделировать это.

  1. Откройте свои инструменты разработчика и щелкните его, чтобы сделать его активным.
  2. Запустите событие для интересующего вас элемента.
  3. Не перемещая мышь, откройте панель команд devtools с помощью ctrl + shift + p и выберите «отключить javascript» с помощью клавиатуры.

Поскольку javascript отключен, у него нет возможности снова изменить элемент (ы). Вы можете перейти в инструменты разработчика и проверить CSS и HTML так, как если бы вы зависали, щелкали или делали с ними что-то еще. После того, как вы закончите, снова перейдите в командную панель и выберите «включить javascript».

Пиепонгвонг
источник
Хорошая техника, но если я не понял ваши намерения, она уже существует в инструментах разработки! В инструментах разработки Chrome / Chromium и Firefox есть :hovкнопка в верхней части инспектора стилей (рядом с полем ввода «Фильтр»). Щелчок :hovрасширяет серию флажков, каждый помечен pseudoclass: :active, :focus, :focus-within, :hover, и :visited. И установка любого из этих флажков активирует соответствующий псевдокласс для проверяемого элемента.
Привет,