Skip to content

Commit 98d6951

Browse files
committed
optimize query selector
1 parent 959bbfd commit 98d6951

File tree

3 files changed

+29
-30
lines changed

3 files changed

+29
-30
lines changed

packages/core/ui/core/dom/src/nodes/element/Element.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1+
import QuerySelector from '../../query-selector/QuerySelector';
12
import { createAttributeFilter, findWhere, splice } from '../../utils';
3+
import XMLParser from '../../xml-parser/XMLParser';
4+
import XMLSerializer from '../../xml-serializer';
25
import type HTMLSlotElement from '../html-slot-element/HTMLSlotElement';
36
import NodeList from '../node/NodeList';
47
import NodeTypeEnum from '../node/NodeTypeEnum';
58
import ParentNode from '../parent-node/ParentNode';
69
import { ShadowHostMixin } from '../shadow-root/ShadowHost';
710
import { ShadowRoot } from '../shadow-root/ShadowRoot';
8-
import XMLParser from '../../xml-parser/XMLParser';
9-
import XMLSerializer from '../../xml-serializer';
10-
import QuerySelector from '../../query-selector/QuerySelector';
1111

1212
/**
1313
* Element.
@@ -163,20 +163,18 @@ export default class Element extends ParentNode {
163163
});
164164

165165
this._shadowRoot = shadow;
166-
167166
const childNodes = this.childNodes;
168167
// Remove any childern from rendered DOM
169168
for (const node of childNodes) {
170169
node.remove();
171170
}
172-
ShadowHostMixin;
173171
// Make this element a Shadow Host.
174-
//Object.assign(this, ShadowHostMixin);
172+
Object.assign(this, ShadowHostMixin);
175173
// // Add childern back to Light DOM
176174
// // If they are slottable, they will
177175
// // get rendered again in the
178176
// // Shadow Tree.
179-
// this.append(...childNodes);
177+
this.append(...childNodes);
180178

181179
return shadow;
182180
}

packages/core/ui/core/dom/src/query-selector/QuerySelector.ts

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export default class QuerySelector {
2424
const matches = new NodeList<Element>();
2525

2626
for (const parts of this.getSelectorParts(selector)) {
27-
for (const element of this.findAll(node, [node], parts)) {
27+
for (const element of this.findAll(node, parts)) {
2828
if (!matches.includes(element)) {
2929
matches.push(element);
3030
}
@@ -43,7 +43,7 @@ export default class QuerySelector {
4343
*/
4444
public static querySelector(node: Node, selector: string): Element {
4545
for (const parts of this.getSelectorParts(selector)) {
46-
const match = this.findFirst(node, [node], parts);
46+
const match = this.findFirst(node, parts);
4747

4848
if (match) {
4949
return match;
@@ -128,33 +128,32 @@ export default class QuerySelector {
128128
* @param [selectorItem] Selector item.
129129
* @returns HTML elements.
130130
*/
131-
private static findAll(rootNode: Node, nodes: Node[], selectorParts: string[], selectorItem?: SelectorItem): Element[] {
131+
private static findAll(rootNode: Node, selectorParts: string[], selectorItem?: SelectorItem): Element[] {
132132
const isDirectChild = selectorParts[0] === '>';
133133
if (isDirectChild) {
134134
selectorParts = selectorParts.slice(1);
135135
}
136136
const selector = selectorItem || new SelectorItem(selectorParts[0]);
137137
let matched = [];
138-
139-
for (const node of nodes) {
138+
let node = rootNode.firstChild;
139+
while (node) {
140140
if (node.nodeType === Node.ELEMENT_NODE) {
141141
if (selector.match(<Element>node).matches) {
142142
if (selectorParts.length === 1) {
143143
if (rootNode !== node) {
144144
matched.push(node);
145145
}
146146
} else {
147-
if (node.firstChild) {
148-
const childMatches = this.findAll(rootNode, (<Element>node).children, selectorParts.slice(1), null);
149-
matched = matched.concat(childMatches);
150-
}
147+
const childMatches = this.findAll(rootNode, selectorParts.slice(1), null);
148+
matched = matched.concat(childMatches);
151149
}
152150
}
153151
}
154152

155153
if (!isDirectChild && node['firstChild']) {
156-
matched = matched.concat(this.findAll(rootNode, node['children'], selectorParts, selector));
154+
matched = matched.concat(this.findAll(rootNode, selectorParts, selector));
157155
}
156+
node = node.nextSibling;
158157
}
159158

160159
return matched;
@@ -170,34 +169,36 @@ export default class QuerySelector {
170169
* @param [selectorItem] Selector item.
171170
* @returns HTML element.
172171
*/
173-
private static findFirst(rootNode: Node, nodes: Node[], selectorParts: string[], selectorItem?: SelectorItem): Element {
172+
private static findFirst(rootNode: Node, selectorParts: string[], selectorItem?: SelectorItem): Element {
174173
const isDirectChild = selectorParts[0] === '>';
175174
if (isDirectChild) {
176175
selectorParts = selectorParts.slice(1);
177176
}
178177
const selector = selectorItem || new SelectorItem(selectorParts[0]);
178+
let node = rootNode.firstChild;
179179

180-
for (const node of nodes) {
180+
while (node) {
181181
if (node.nodeType === Node.ELEMENT_NODE && selector.match(<Element>node).matches) {
182182
if (selectorParts.length === 1) {
183183
if (rootNode !== node) {
184184
return <Element>node;
185185
}
186186
} else {
187-
const childSelector = this.findFirst(rootNode, (<Element>node).children, selectorParts.slice(1), null);
187+
const childSelector = this.findFirst(rootNode, selectorParts.slice(1), null);
188188
if (childSelector) {
189189
return childSelector;
190190
}
191191
}
192192
}
193193

194194
if (!isDirectChild && node['firstChild']) {
195-
const childSelector = this.findFirst(rootNode, node['children'], selectorParts, selector);
195+
const childSelector = this.findFirst(rootNode, selectorParts, selector);
196196

197197
if (childSelector) {
198198
return childSelector;
199199
}
200200
}
201+
node = node.nextSibling;
201202
}
202203

203204
return null;

packages/core/ui/core/dom/src/query-selector/SelectorItem.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ const ID_REGEXP = /(?<!\\)#[A-Za-z][-A-Za-z0-9_]*/g;
1111
const CSS_ESCAPE_REGEXP = /(?<!\\):/g;
1212
const CSS_ESCAPE_CHAR_REGEXP = /\\/g;
1313

14+
const PsuedoRegex = new RegExp(PSUEDO_REGEXP, 'g');
15+
const AttributeRegex = new RegExp(ATTRIBUTE_REGEXP, 'g');
16+
const ClassRegex = new RegExp(CLASS_REGEXP, 'g');
1417
/**
1518
* https://github.com/capricorn86/happy-dom/blob/master/packages/happy-dom/src/query-selector/SelectorItem.ts
1619
* Selector item.
@@ -95,7 +98,6 @@ export default class SelectorItem {
9598
if (this.isPseudo && !this.matchesPsuedo(element, selector)) {
9699
return { priorityWeight: 0, matches: false };
97100
}
98-
99101
// Attribute match
100102
if (this.isAttribute) {
101103
const result = this.matchesAttribute(element, selector);
@@ -104,7 +106,6 @@ export default class SelectorItem {
104106
return { priorityWeight: 0, matches: false };
105107
}
106108
}
107-
108109
return { priorityWeight, matches: true };
109110
}
110111

@@ -116,7 +117,7 @@ export default class SelectorItem {
116117
* @returns True if it is a match.
117118
*/
118119
private matchesPsuedo(element: Element, selector: string): boolean {
119-
const regexp = new RegExp(PSUEDO_REGEXP, 'g');
120+
const regexp = PsuedoRegex;
120121
let match: RegExpMatchArray;
121122

122123
while ((match = regexp.exec(selector))) {
@@ -251,7 +252,7 @@ export default class SelectorItem {
251252
* @returns Result.
252253
*/
253254
private matchesAttribute(element: Element, selector: string): { priorityWeight: number; matches: boolean } {
254-
const regexp = new RegExp(ATTRIBUTE_REGEXP, 'g');
255+
const regexp = AttributeRegex;
255256
let match: RegExpMatchArray;
256257
let priorityWeight = 0;
257258

@@ -276,15 +277,14 @@ export default class SelectorItem {
276277
* @returns Result.
277278
*/
278279
private matchesClass(element: Element, selector: string): { priorityWeight: number; matches: boolean } {
279-
const regexp = new RegExp(CLASS_REGEXP, 'g');
280-
const classList = element.className.split(' ');
281-
const classSelector = selector.split(CSS_ESCAPE_REGEXP)[0];
280+
const regexp = ClassRegex;
281+
const classList = element.className;
282+
const classSelector = selector;
282283
let priorityWeight = 0;
283284
let match: RegExpMatchArray;
284-
285285
while ((match = regexp.exec(classSelector))) {
286286
priorityWeight += 10;
287-
if (!classList.includes(match[1].replace(CSS_ESCAPE_CHAR_REGEXP, ''))) {
287+
if (!classList.includes(match[1])) {
288288
return { priorityWeight: 0, matches: false };
289289
}
290290
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy