简体   繁体   English

如何在激活 CSS ":hover" 的纯 JavaScript 中模拟鼠标悬停?

[英]How do I simulate a mouseover in pure JavaScript that activates the CSS ":hover"?

I've been trying to find code to simulate mouseover in Chrome but even though the "mouseover" listener gets fired, the CSS "hover" declaration is never set!我一直在尝试在 Chrome 中找到模拟mouseover的代码,但即使“鼠标悬停”侦听器被触发,CSS“悬停”声明也永远不会设置!

I tried also doing:我也尝试过:

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

But nothing seems to change the element to what is declared in its hover declaration.但是似乎没有任何东西可以将元素更改为其hover声明中声明的内容。

Is this possible?这可能吗?

You can't.你不能。 It's not a trusted event .这不是可信事件

Events that are generated by the user agent, either as a result of user interaction, or as a direct result of changes to the DOM, are trusted by the user agent with privileges that are not afforded to events generated by script through the DocumentEvent.createEvent("Event") method, modified using the Event.initEvent() method, or dispatched via the EventTarget.dispatchEvent() method.由用户代理生成的事件,无论是作为用户交互的结果,还是作为对 DOM 更改的直接结果,都被用户代理信任,其特权是脚本通过 DocumentEvent.createEvent 生成的事件所没有的("Event") 方法,使用 Event.initEvent() 方法修改,或通过 EventTarget.dispatchEvent() 方法调度。 The isTrusted attribute of trusted events has a value of true, while untrusted events have a isTrusted attribute value of false.可信事件的 isTrusted 属性值为 true,而非可信事件的 isTrusted 属性值为 false。

Most untrusted events should not trigger default actions , with the exception of click or DOMActivate events.大多数不受信任的事件不应触发默认操作,但单击或 DOMActivate 事件除外。

You have to add a class and add/remove that on the mouseover/mouseout events manually.您必须添加一个类并在鼠标悬停/鼠标移出事件上手动添加/删除它。

You can simulate the mouseover event like this:您可以像这样模拟鼠标悬停事件:

HTML HTML

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

JavaScript 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);

Background背景

I stumbled upon this question while trying to write automated tests, to verify, that a certain set of elements on a given page all receive have the some set of css properties set by the css for on hover events.我在尝试编写自动化测试时偶然发现了这个问题,以验证给定页面上的特定元素集是否都接收了由 css 为悬停事件设置的一些 css 属性集。

While the above answer perfectly explains, why it is not possible to simply trigger the hover event by JS and then probe some css value of interest, it does answer the initial question "How do I simulate a mouseover in pure JavaScript that activates the CSS “:hover”?"虽然上面的答案完美地解释了为什么不能简单地通过 JS 触发悬停事件然后探测一些感兴趣的 css 值,但它确实回答了最初的问题“我如何在纯 JavaScript 中模拟鼠标悬停来激活 CSS” :徘徊”?” only partly.只是部分。

Disclaimer免责声明

This is not a performant solution.这不是一个高性能的解决方案。 We use it only for automated testing, where performance is not a concern.我们仅将它用于自动化测试,其中性能不是问题。

Solution解决方案

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

Explanation解释

generateEvent reads all css files, , replaces :hover with an empty string and applies it. generateEvent 读取所有 css 文件,将 :hover 替换为空字符串并应用它。 This has the effect, that all :hover styles are applied.这具有应用所有 :hover 样式的效果。 Now one can probe for a howered style and set back to initial state by stopping the Simulation.现在,您可以通过停止模拟来探索一种咆哮的风格并设置回初始状态。

Why do we apply the hover effect for the whole document and not just for the element of interest by getting the from the sheets and then perform a element.css(...)?为什么我们通过从工作表中获取 ,然后执行 element.css(...) 来对整个文档应用悬停效果,而不仅仅是对感兴趣的元素应用?

Done as that, the style would be applied inline, this would override other styles, which might not be overriden by the original css hover-style.这样做后,样式将被内联应用,这将覆盖其他样式,这些样式可能不会被原始 css 悬停样式覆盖。

How would I now simulate the hover for a single element?我现在如何模拟单个元素的悬停?

This is not performant, so better don't.这不是高性能的,所以最好不要。 If you must, you could check with the element.is(selectorOfInterest) if the style applies for your element and only use those styles.如果必须,您可以使用 element.is(selectorOfInterest) 检查样式是否适用于您的元素并且仅使用这些样式。

Example例子

In Jasmine you can eg now perform:在 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");
    });
});

What I usually do in this case is adding a class using javascript.. and attaching the same CSS as the :hover to this class在这种情况下,我通常做的是使用 javascript 添加一个类……并将与:hover相同的CSS附加到这个类

Try using尝试使用

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

Or for older browsers:或者对于较旧的浏览器:

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

you will of course have to use onmouseout to remove the "hovered" class when you leave the element...当您离开元素时,您当然必须使用onmouseout删除“悬停”类......

You can use pseudo:styler , a library which can apply CSS pseudo-classes to elements.您可以使用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');
  })
})();

Disclaimer: I am a coauthor of this library.免责声明:我是这个库的合著者。 We designed it to additionally support cross-origin stylesheets, specifically for use in Chrome extensions where you likely lack control over the CSS rules of the page.我们将其设计为额外支持跨源样式表,特别是在 Chrome 扩展程序中使用,您可能无法控制页面的 CSS 规则。

I'm assuming you want to inspect the CSS after dom manipulation, but as soon as you move your mouse back to the devtools, the event isn't active on that html element anymore.我假设您想在 dom 操作之后检查 CSS,但是一旦您将鼠标移回 devtools,该事件就不再在该 html 元素上处于活动状态。 You probably would like to have something like the :hover option in devtools for your javascript events.您可能希望在 devtools 中为您的 javascript 事件提供类似 :hover 选项的东西。 That doesn't exist, but you can simulate it.那不存在,但您可以模拟它。

  1. Open your devtools and click in it to make it active.打开您的开发工具并单击它以使其处于活动状态。
  2. Trigger the event on the element you're interested in.在您感兴趣的元素上触发事件。
  3. Without moving the mouse, open the devtools command panel with ctrl + shift + p and select 'disable javascript' with your keyboard.在不移动鼠标的情况下,使用 ctrl + shift + p 打开 devtools 命令面板,然后使用键盘选择“禁用 javascript”。

Since javascript is disabled, it doesn't get the chance to modify the element(s) back again.由于 javascript 被禁用,它没有机会再次修改元素。 You can go to the devtools and inspect the css and html as if you were hovering, clicking or doing something else with it.您可以转到 devtools 并检查 css 和 html,就像您悬停、单击或使用它做其他事情一样。 After you're done, go to the command panel again and select 'enable javascript'.完成后,再次转到命令面板并选择“启用 javascript”。

SCSS SCSS

.hover {
    @extend :hover;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM