在document.ready()上选择:target [英] Selecting :target on document.ready()
问题描述
以下是一个简单的测试用例,以演示我正在尝试做的事情:
< html>< head>< title> Test</title></head><身体>< script src ="http://code.jquery.com/jquery-1.10.1.min.js"></script>< script type ="text/javascript">$ {document).ready(function(){$(:target").css('color','red');});</script>< ul>< li id ="one">一个</li>< li id ="two"> Two</li>< li id ="three">三个</li></ul></body></html>
这个想法是当目标被定位时(例如,test.html#two)通过jQuery/Javascript对目标项目进行操作.
这可以在Firefox和IE 10中正常运行,但不能在Chrome,Opera或Safari中运行,这让我想知道这是否是某些浏览器中的错误,如果我尝试做的是某种错误,或者如果我遇到某些规范或其他规范中不够精确的部分的话.
如果我将jQuery代码更改为
alert($(:target").length);
很明显,Chrome,Opera和Safari在document.ready()期间找不到:target元素,但是稍后(通过控制台或附加到click事件的函数)调用相同的代码会找到这些元素./p>
:target应该何时可以被JS访问?
此内容已发布为评论,但后来被删除,您可以尝试等待窗口加载事件:
$(window).on('load hashchange',function(){$(':target').css('color','red');});
这对我来说在Chrome上产生了不同的结果,在刷新页面(F5)时有效,但在地址栏中按Enter键却无效.
我不知道是否可以使用:target
选择器在页面加载时正确处理此问题,但是您始终可以获取哈希值并将其用作选择器:
$(window).on('load hashchange',function(){var target = window.location.hash;$(target).css('color','red');});
更新
我一直在对该问题进行一些研究,并进行了一些测试,我有几点见解可以分享:
首先,我们需要了解,在调用 $(':target')
时,jQuery内部使用了 querySelectorAll(':target')
,这意味着直接与伪类的CSS规范有关,但是为什么在 document.ready()
内部不起作用?
好吧,我发现将代码包装在 setTimeout(fn,0)
中实际上使选择器可用:
$(document).ready(function(){setTimeout(function(){$(':target').css('color','red');//此工作},0);});
您可以阅读此答案,以获取有关添加零毫秒超时实际上有何不同的解释,但基本上它允许浏览器完成其他与JavaScript无关的任务(在这些任务中,我们会发现使实际的CSS伪类可用于查询).我相信Firefox以某种方式对内部流程进行不同的管理,这就是为什么代码在那里无需超时即可工作的原因.
现在,我还发现jQuery的内部sizzle选择器引擎为不支持CSS :target
伪类的浏览器提供了后备功能,您可以在 document.ready()
没问题:
$(document).ready(function(){$(':target()').css('color','red');});
之所以可行,是因为它不是依赖CSS类,而是一个JavaScript实现,它利用window.location对象上的hash属性,在内部对其进行了如下定义:
"target":function(elem){var hash = window.location&&window.location.hash;返回哈希&&hash.slice(1)=== elem.id;}
您唯一需要注意的是,如果未传递:target(div)
之类的选择器,则此函数将遍历页面上的每个元素,因此我相信使用我之前提供的解决方法还是比这更好的选择.
The following is a simple test case to demonstrate what I'm trying to do:
<html>
<head>
<title>Test</title>
</head>
<body>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script type="text/javascript">
$(document).ready(function()
{
$(":target").css('color', 'red');
});
</script>
<ul>
<li id="one">One</li>
<li id="two">Two</li>
<li id="three">Three</li>
</ul>
</body>
</html>
The idea is to do something through jQuery/Javascript to the targetted item, when something is targetted (for example, test.html#two).
This works as I expect it to in Firefox and IE 10, but not in Chrome, Opera or Safari, which leaves me wondering if this is a bug in some browsers, if what I'm trying to do is somehow wrong, or if I've run afoul of an inadequately precise part of some specification or other.
If I change the jQuery code to do
alert($(":target").length);
it becomes apparent that Chrome, Opera and Safari can't find the :target element during document.ready(), but calling the same code later (via console or function attached to a click event) does find the elements.
When should :target become accessible to JS?
This was posted as a comment but was later removed, you can try waiting for the window load event:
$(window).on('load hashchange', function(){
$(':target').css('color', 'red');
});
This for me produced mixed results on Chrome, it worked when doing a page refresh (F5) but not when hitting enter in the address bar.
I don't know if there's any way to handle this correctly on page load using the :target
selector but you could always get the hash value and use it as your selector:
$(window).on('load hashchange', function(){
var target = window.location.hash;
$(target).css('color', 'red');
});
UPDATE
I've been doing some research on the issue plus some tests and I have a couple of insights to share:
First off, we need to understand that when calling $(':target')
jQuery internally makes use of querySelectorAll(':target')
which means it's directly related to the CSS specification of the pseudo-class, but why isn't working inside document.ready()
?
Well, I found that wrapping the code inside setTimeout(fn,0)
actually makes the selector available:
$(document).ready(function(){
setTimeout(function(){
$(':target').css('color', 'red'); //THIS WORKS
},0);
});
You can read this answer for an explanation on how adding a zero-ms timeout actually makes a difference, but basically it allows the browser to complete other non-javascript related tasks (in which we would find making the actual CSS pseudo-class available for query). I believe Firefox somehow manages its internal processes differently and that's why the code works there without the need for a timeout.
Now I also discovered that jQuery's internal sizzle selector engine provides a fallback for browsers that do not support CSS :target
pseudo-class, which you can use inside document.ready()
without issue:
$(document).ready(function(){
$(':target()').css('color', 'red');
});
This works because instead of relying on the CSS class it is a javascript implementation that makes use of the hash property on the window.location object, internally it is defined as follows:
"target": function( elem ) {
var hash = window.location && window.location.hash;
return hash && hash.slice( 1 ) === elem.id;
}
The only think you should note is that this function will go through every element on the page if it's not passed a selector like :target(div)
, so I believe using the workaround I provided earlier would still be a better option than this.
这篇关于在document.ready()上选择:target的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!