Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitdf6a7f7

Browse files
authored
Selector: Leverage the :scope pseudo-class where possible
The `:scope` pseudo-class[1] has surprisingly good browser support: Chrome,Firefox & Safari have supported if for a long time; only IE & Edge lack support.This commit leverages this pseudo-class to get rid of the ID hack in most cases.Adding a temporary ID may cause layout thrashing which was reported a few timesin [the past.We can't completely eliminate the ID hack in modern browses as sibling selectorsrequire us to change context to the parent and then `:scope` stops applying towhat we'd like. But it'd still improve performance in the vast majority ofcases.[1]https://developer.mozilla.org/en-US/docs/Web/CSS/:scopeFixesgh-4453Closesgh-4454Refgh-4332Refjquery/sizzle#405
1 parent7bdf307 commitdf6a7f7

File tree

4 files changed

+107
-18
lines changed

4 files changed

+107
-18
lines changed

‎src/selector.js

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ define( [
44
"./var/indexOf",
55
"./var/pop",
66
"./var/push",
7+
"./selector/support",
78

89
// The following utils are attached directly to the jQuery object.
910
"./selector/contains",
1011
"./selector/escapeSelector",
1112
"./selector/uniqueSort"
12-
],function(jQuery,document,indexOf,pop,push){
13+
],function(jQuery,document,indexOf,pop,push,support){
1314

1415
"use strict";
1516

@@ -230,24 +231,30 @@ function find( selector, context, results, seed ) {
230231
// Thanks to Andrew Dupont for this technique.
231232
if(nodeType===1&&rdescend.test(selector)){
232233

233-
// Capture the context ID, setting it first if necessary
234-
if((nid=context.getAttribute("id"))){
235-
nid=jQuery.escapeSelector(nid);
236-
}else{
237-
context.setAttribute("id",(nid=expando));
234+
// Expand context for sibling selectors
235+
newContext=rsibling.test(selector)&&testContext(context.parentNode)||
236+
context;
237+
238+
// We can use :scope instead of the ID hack if the browser
239+
// supports it & if we're not changing the context.
240+
if(newContext!==context||!support.scope){
241+
242+
// Capture the context ID, setting it first if necessary
243+
if((nid=context.getAttribute("id"))){
244+
nid=jQuery.escapeSelector(nid);
245+
}else{
246+
context.setAttribute("id",(nid=expando));
247+
}
238248
}
239249

240250
// Prefix every selector in the list
241251
groups=tokenize(selector);
242252
i=groups.length;
243253
while(i--){
244-
groups[i]="#"+nid+" "+toSelector(groups[i]);
254+
groups[i]=(nid ?"#"+nid :":scope")+" "+
255+
toSelector(groups[i]);
245256
}
246257
newSelector=groups.join(",");
247-
248-
// Expand context for sibling selectors
249-
newContext=rsibling.test(selector)&&testContext(context.parentNode)||
250-
context;
251258
}
252259

253260
try{

‎src/selector/support.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
define([
2+
"../var/document",
3+
"../var/support"
4+
],function(document,support){
5+
6+
"use strict";
7+
8+
// Support: IE 9 - 11+, Edge 12 - 18+
9+
// IE/Edge don't support the :scope pseudo-class.
10+
try{
11+
document.querySelectorAll(":scope");
12+
support.scope=true;
13+
}catch(e){}
14+
15+
returnsupport;
16+
17+
});

‎test/unit/selector.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1631,6 +1631,41 @@ QUnit.test( "context", function( assert ) {
16311631
}
16321632
});
16331633

1634+
// Support: IE 11+, Edge 12 - 18+
1635+
// IE/Edge don't support the :scope pseudo-class so they will trigger MutationObservers.
1636+
// The test is skipped there.
1637+
QUnit[
1638+
(QUnit.isIE||/edge\//i.test(navigator.userAgent)) ?
1639+
"skip" :
1640+
"test"
1641+
]("selectors maintaining context don't trigger mutation observers",function(assert){
1642+
assert.expect(1);
1643+
1644+
vartimeout,
1645+
done=assert.async(),
1646+
container=jQuery("<div/>"),
1647+
child=jQuery("<div/>");
1648+
1649+
child.appendTo(container);
1650+
container.appendTo("#qunit-fixture");
1651+
1652+
varobserver=newMutationObserver(function(){
1653+
clearTimeout(timeout);
1654+
observer.disconnect();
1655+
assert.ok(false,"Mutation observer fired during selection");
1656+
done();
1657+
});
1658+
observer.observe(container[0],{attributes:true});
1659+
1660+
container.find("div div");
1661+
1662+
timeout=setTimeout(function(){
1663+
observer.disconnect();
1664+
assert.ok(true,"Mutation observer didn't fire during selection");
1665+
done();
1666+
});
1667+
});
1668+
16341669
QUnit.test("caching does not introduce bugs",function(assert){
16351670
assert.expect(3);
16361671

‎test/unit/support.js

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,24 @@ testIframe(
5858
varexpected,
5959
userAgent=window.navigator.userAgent,
6060
expectedMap={
61-
edge:{},
62-
ie_11:{},
63-
chrome:{},
64-
safari:{},
65-
firefox:{},
66-
ios:{}
61+
edge:{
62+
scope:undefined
63+
},
64+
ie_11:{
65+
scope:undefined
66+
},
67+
chrome:{
68+
scope:true
69+
},
70+
safari:{
71+
scope:true
72+
},
73+
firefox:{
74+
scope:true
75+
},
76+
ios:{
77+
scope:true
78+
}
6779
};
6880

6981
if(/edge\//i.test(userAgent)){
@@ -95,6 +107,15 @@ testIframe(
95107
j++;
96108
}
97109

110+
// Add an assertion per undefined support prop as it may
111+
// not even exist on computedSupport but we still want to run
112+
// the check.
113+
for(propinexpected){
114+
if(expected[prop]===undefined){
115+
j++;
116+
}
117+
}
118+
98119
assert.expect(j);
99120

100121
for(iinexpected){
@@ -116,14 +137,23 @@ testIframe(
116137
i++;
117138
}
118139

140+
// Add an assertion per undefined support prop as it may
141+
// not even exist on computedSupport but we still want to run
142+
// the check.
143+
for(propinexpected){
144+
if(expected[prop]===undefined){
145+
i++;
146+
}
147+
}
148+
119149
assert.expect(i);
120150

121151
// Record all support props and the failing ones and ensure every test
122152
// is failing at least once.
123153
for(browserKeyinexpectedMap){
124154
for(supportTestNameinexpectedMap[browserKey]){
125155
supportProps[supportTestName]=true;
126-
if(expectedMap[browserKey][supportTestName]!==true){
156+
if(!expectedMap[browserKey][supportTestName]){
127157
failingSupportProps[supportTestName]=true;
128158
}
129159
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp