“:active”伪类什么时候被应用?

5

我试图使用querySelector在页面中查找活动元素。我假设绑定到文档上mousedown事件的处理函数会在事件从目标元素冒泡回来后触发,也就是说:active伪类应该已经被应用了。

document.addEventListener("mousedown",function(e){

    console.log(document.querySelector("*:active"));// logs null

    // expected value was the target of the mousedown event, that is,
    console.log(e.target);

});

我的问题是:什么时候会准确地应用:active伪类?请注意,当我记录该值时,mousedown事件已经在目标上触发。
请参见http://jsfiddle.net/tK67w/2/以获取示例。有趣的是,如果您在处理程序中设置断点,则可以看到我为a:active定义的css规则已经应用,尽管querySelector返回null 编辑:
感谢TJ提供了一个更好的演示。然而问题仍然存在:在IE和Chrome以外的浏览器中,如何获取所有活动元素的HTMLCollection,因为它们变为活动状态?

它不会向我记录“null”,而是记录HTML元素。而e.target记录了锚点。 - bfavaretto
@bfavaretto 或许这是一个浏览器特定的问题?我正在使用 Firefox。e.target 确实记录了锚点,但第一个记录了 *null*。 - Asad Saeeduddin
2个回答

2
我认为问题在于您使用了querySelector,这只会获取第一个活动元素。但是您的锚点要远得多。 更新:有趣的是,我在Firefox或Opera中什么都没有得到,但是在Chrome中却有。以下是Chrome结果。请参见下面的更多信息。
考虑以下内容(实时演示):
document.addEventListener("mousedown", handler, false);
function handler(e){
    console.log(
        "event " + e.type + ": " +
        Array.prototype.join.call(document.querySelectorAll("*:active")));
}​

当我点击锚点时,控制台会显示以下内容:
事件mousedown:[object HTMLHtmlElement],[object HTMLBodyElement],[object HTMLDivElement],http://fiddle.jshell.net/_display/#
请注意末尾的URL,它是HTMLAnchroElement实例的默认toString,由join触发。
由于querySelectorAll需要按文档顺序返回元素,如果要获取最具体的活动元素,则应该使用最后一个。例如(实时演示):
(function() {
    document.addEventListener("mousedown",handler, false);

    function handler(e){
        var active = document.querySelectorAll("*:active");
        var specific = active && active.length && active[active.length-1];
        display("Most specific active element: " +
                (specific ? specific.tagName : "(none)"));
    }

    function display(msg) {
        var p = document.createElement('p');
        p.innerHTML = String(msg);
        document.body.appendChild(p);
    }
})();
​

在我的情况下(使用Chrome),如果我点击链接,我会看到最具体元素的标签名称(锚点等)。
看起来Chrome正在遵循规范,而Firefox和Opera没有。从CSS3选择器规范的第6.6.1.2节中可以看出:

:active 伪类应用于用户激活元素时。例如,在用户按下鼠标按钮和释放它之间。

因此,在上面的情况下应该应用 :active。如果我们使用以下CSS,则支持这种断言:
*:active {
    background-color: red;
}

使用以下JavaScript代码:

(function() {
    document.addEventListener("mousedown", mouseDown, false);
    document.addEventListener("mouseup", mouseUp, false);

    function mouseDown(){
        var active = document.querySelectorAll("*:active");
        var specific = active && active.length && active[active.length-1];
        display("Mouse down: Most specific active element: " +
                (specific ? specific.tagName : "(none)"));
    }

    function mouseUp() {
        display("Mouse up");
    }

    function display(msg) {
        var p = document.createElement('p');
        p.innerHTML = String(msg);
        document.body.appendChild(p);
    }
})();

现场演示

我尝试了三种浏览器(Chrome,Firefox,Opera),当鼠标按下时,元素会变成红色背景,并在释放后变为白色;但是mousedown处理程序在Firefox或Opera中看不到:active元素,只有Chrome可以。

但我不是CSS规范的律师。 :-)


在我的控制台中,我看到:event mousedown:。我正在使用Firefox浏览器。 - Asad Saeeduddin
@Asad:有趣,浏览器似乎存在差异。Chrome会给我列出列表。 - T.J. Crowder
@Asad:当你将CSS *:active {...} 而不是 span:active 时,会变得更加有趣(尤其是因为在你的fiddle中没有span)。它会在鼠标按下时应用,但处理程序仍然无法在 querySelector(All) 中看到它。 - T.J. Crowder
是的,当我将我的问题简化为一个例子时,span 是一个疏忽。我最初使用了 span。我已经在问题中提到了这种行为。 - Asad Saeeduddin
我不知道,规范并没有真正定义浏览器中“activated”是什么意思,只是给出了一个可能的例子。也许存在很多不一致性(虽然我不是说这样做是可以接受的...)。Web API WG或CSSWG邮件列表是一个不错的询问地点。 - BoltClock
显示剩余6条评论

0

看起来是在帧被渲染之后设置的,或者可能是在当前执行队列之后,至少在Firefox中是这样。

使用没有延迟的setTimeout获得了结果(requestAnimationFrame也可以使用):

document.addEventListener('mousedown', e => {

  setTimeout(_ => console.log(document.querySelectorAll(':active')));

});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接