如何在纯 JavaScript 中模拟鼠标悬停以激活 CSS“:hover”?

IT技术 javascript jquery css
2021-02-05 21:34:55

我一直在尝试寻找mouseover在 Chrome 中模拟的代码,但即使“鼠标悬停”侦听器被触发,CSS“悬停”声明也从未设置!

我也试过这样做:

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

但是似乎没有什么可以将元素更改为其hover声明中声明的内容。

这可能吗?

6个回答

你不能。这不是可信事件

由用户代理生成的事件,无论是作为用户交互的结果,还是作为对 DOM 更改的直接结果,都被用户代理信任,并且具有脚本通过 DocumentEvent.createEvent 生成的事件所没有的特权("Event") 方法,使用 Event.initEvent() 方法修改,或通过 EventTarget.dispatchEvent() 方法调度。可信事件的 isTrusted 属性值为 true,而非可信事件的 isTrusted 属性值为 false。

大多数不受信任的事件不应触发默认操作,但单击或 DOMActivate 事件除外。

您必须添加一个类并在鼠标悬停/鼠标移出事件上手动添加/删除它。

@Pacerier 这不是受信任的事件,因为它不是由用户发起的。它是这么说的那里,在我的回答上面的报价。这就是答案的开头。
2021-03-13 21:34:55
是的,尽管听起来很荒谬,但您可以使焦点看起来是由用户交互引起的,而实际上并非如此。在实践中 - 浏览器 API 会很乐意违反规范并忽略焦点和点击作为不受信任的事件(至少是 Chrome)。例如,尝试模拟点击 chrome 扩展的扩展安装按钮,看看会发生什么:)
2021-04-01 21:34:55
@Tim,它实际上并没有回答为什么它只是改变了问题
2021-04-06 21:34:55
@BenjaminGruenbaum,我引用的是“点击或 DOMActivate 事件除外”“悬停”有什么特别之处以至于它不在此例外列表中?为什么我们可以调用“focus”而不是“hover”?这些是我们必须回答的问题,回答任何其他问题只是在改变问题
2021-04-07 21:34:55
我认为悬停(并结合单击或鼠标向上和向下拖放)可能表现或看起来像劫持用户的系统(如果您忽略自动化案例),因此支持它并不理想。单击我不能说,但焦点将允许自动聚焦到站点设计者希望用户关注的目标表单字段或元素,例如缺少或不正确数据的文本字段(例如表单字段验证检查)。但这只是我的假设。
2021-04-09 21:34:55

您可以像这样模拟鼠标悬停事件:

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);
谢谢,我只需要泡泡!在开发者控制台检查器中右键单击一个元素,然后执行“在控制台中使用”(Firefox) 或“存储为全局变量”(Chrome)。然后,您可以,例如, temp0.dispatchEvent(new MouseEvent('mouseover', {bubbles: true})) 对于样式化工具提示或仅在鼠标悬停时出现的其他内容非常有用。
2021-03-23 21:34:55
@DenisHowe 对于该用例,您应该查看:hovdevtools 中样式检查器顶部按钮。它允许您在被检查的元素上激活您喜欢的任何伪类。
2021-04-08 21:34:55

背景

我在尝试编写自动化测试时偶然发现了这个问题,以验证给定页面上的特定元素集是否都接收了由 css 为悬停事件设置的一些 css 属性集。

虽然上面的答案完美地解释了为什么不能简单地通过 JS 触发悬停事件然后探测一些感兴趣的 css 值,但它确实回答了最初的问题“我如何在纯 JavaScript 中模拟鼠标悬停来激活 CSS” :徘徊”?” 只是部分。

免责声明

这不是一个高性能的解决方案。我们仅将它用于自动化测试,其中性能不是问题。

解决方案

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");
    });
});
这个答案很棒!不幸的是,由于 Chrome 限制了对跨域请求的访问,它在具有从其他主机提供的样式表的页面上的最新版本的 Chrome 上失败。请参阅我的答案以获取支持此功能的解决方案:)
2021-03-28 21:34:55

我最常做在这种情况下是使用JavaScript添加类..和将相同CSS:hover这一类

尝试使用

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

或者对于较旧的浏览器:

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

onmouseout当您离开元素时,您当然必须使用删除“悬停”类...

还不够好?它是“纯”JavaScript,实际上它会附加一个函数作为事件的处理程序。在 Internet Explorer 中,将使用(几乎)等效项attachEvent()
2021-03-17 21:34:55
@Pointy 问题要求使用纯 javascript .. 否则如何附加事件?
2021-03-21 21:34:55
值得一提。IE9 和 10 支持addEventListener,这是附加事件的最佳方式,attachEvent仅在 IE8(及更低版本)中才需要填充。Yotam,如果他onmouseover通过直接设置属性(而不是添加事件侦听器)添加另一个处理程序,它将覆盖当前设置的事件。请参阅有关差异的问题
2021-03-23 21:34:55
这不会按照 OP 的要求执行,尽管它可能或多或少是正确的。最好使用现代事件处理程序附件技术。
2021-03-27 21:34:55
抱歉,误解了问题
2021-04-08 21:34:55

您可以使用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 规则。

这似乎实际上工作得相当好,即使window.getComputedStyle(<youElement>)在设置伪样式后结合使用也是如此。谢谢!
2021-03-26 21:34:55