Interpreter mode (Interpreter): defines a syntax format, implements it through program interpretation and completes the corresponding task. In front-end programming scenarios, you can apply the interpreter mode to interpret the CSS selector for DOM element selection.
Open and closed Principle: The open and closed principle in object-oriented systems is that classes or modules should be open to modify and close extensions. In this dom selector, id selector, element selector, and class selector are implemented, if you need an attribute selector later, define an attribute selector to implement the corresponding method, and add the corresponding branch of the property selector object in a simple factory.
Matching Principle: The browser matches the CSS selector from right to left, so the matching behavior should be consistent with that of the browser native when implementing its own DOM selector.
Code:Copy codeThe Code is as follows: (function (ns ){
/*
// TagName
Console. log (dom. get ("p "));
// # Id
Console. log (dom. get ("# div "));
//. Class
Console. log (dom. get (". span", document. body ));
// Tag. class
Console. log (dom. get ("div. span "));
// # Id. class
Console. log (dom. get ("# div. span "));
//. Class. class
Console. log (dom. get (". ul. li-test "));
*/
Var doc = document;
Var simple =/^ (? : # | \.)? ([\ W-_] + )/;
Function api (query, context ){
Context = context | doc;
// Call the native Selector
If (! Simple. test (query) & context. querySelectorAll ){
Return context. querySelectorAll (query );
} Else {
// Call the custom Selector
Return interpret (query, context );
}
}
// Explain the execution dom selector.
Function interpret (query, context ){
Var parts = query. replace (/\ s +/, ""). split ("");
Var part = parts. pop ();
Var selector = Factory. create (part );
Var ret = selector. find (context );
Return (parts [0] & ret [0])? Filter (parts, ret): ret;
}
// ID Selector
Function IDSelector (id ){
This. id = id. substring (1 );
}
IDSelector. prototype = {
Find: function (context ){
Return document. getElementById (this. id );
},
Match: function (element ){
Return element. id = this. id;
}
};
IDSelector. test = function (selector ){
Var regex =/^ # ([\ w \-_] + )/;
Return regex. test (selector );
};
// Element Selector
Function TagSelector (tagName ){
This. tagName = tagName. toUpperCase ();
}
TagSelector. prototype = {
Find: function (context ){
Return context. getElementsByTagName (this. tagName );
},
Match: function (element ){
Return this. tagName = element. tagName. toUpperCase () | this. tagName = "*";
}
};
TagSelector. test = function (selector ){
Var regex =/^ ([\ w \ * \-_] + )/;
Return regex. test (selector );
};
// Class selector
Function ClassSelector (className ){
Var splits = className. split ('.');
This. tagName = splits [0] | undefined;
This. className = splits [1];
}
ClassSelector. prototype = {
Find: function (context ){
Var elements;
Var ret = [];
Var tagName = this. tagName;
Var className = this. className;
Var selector = new TagSelector (tagName | "*"));
// Supports native getElementsByClassName
If (context. getElementsByClassName ){
Elements = context. getElementsByClassName (className );
If (! TagName ){
Return elements;
}
For (var I = 0, n = elements. length; I <n; I ++ ){
If (selector. match (elements [I]) {
Ret. push (elements [I]);
}
}
} Else {
Elements = selector. find (context );
For (var I = 0, n = elements. length; I <n; I ++ ){
If (this. match (elements [I]) {
Ret. push (elements [I]);
}
}
}
Return ret;
},
Match: function (element ){
Var className = this. className;
Var regex = new RegExp ("^ | \ s" + className + "$ | \ s ");
Return regex. test (element. className );
}
};
ClassSelector. test = function (selector ){
Var regex =/^ ([\ w \-_] + )? \. ([\ W \-_] + )/;
Return regex. test (selector );
};
// TODO: attribute Selector
Function AttributeSelector (attr ){
This. find = function (context ){
};
This. match = function (element ){
};
}
AttributeSelector. test = function (selector ){
Var regex =/\ [([\ w \-_] + )(? : = ([\ W \-_] + ))? \]/;
Return regex. test (selector );
};
// Filter by parent Element
Function filter (parts, nodeList ){
Var part = parts. pop ();
Var selector = Factory. create (part );
Var ret = [];
Var parent;
For (var I = 0, n = nodeList. length; I <n; I ++ ){
Parent = nodeList [I]. parentNode;
While (parent & parent! = Doc ){
If (selector. match (parent )){
Ret. push (nodeList [I]);
Break;
}
Parent = parent. parentNode;
}
}
Return parts [0] & ret [0]? Filter (parts, ret): ret;
}
// Create a selector object based on the query selector.
Var Factory = {
Create: function (query ){
If (IDSelector. test (query )){
Return new IDSelector (query );
} Else if (ClassSelector. test (query )){
Return new ClassSelector (query );
} Else {
Return new TagSelector (query );
}
}
};
Ns. dom | (ns. dom = {});
Ns. dom. get = api;
} (This ));