JavaScript implements DOM object Selector _javascript Tips

Source: Internet
Author: User
Tags new set

Objective:

Select the first conforming DOM object based on the incoming selector type.
① can get DOM objects, such as $ ("#adom") by ID;
② can get DOM objects, such as $ ("a"), through tagname;
③ can get a DOM object, such as $ (". ClassA"), by a style name;
④ can get DOM objects by attribute matching, such as $ ("[Data-log]"), $ ("[data-time=2015]");
⑤ can get DOM objects, such as $ ("#adom. ClassA") through cascading combinations;

idea:

It is necessary to distinguish the compound selection from the single one, and the individual selection is obtained by the respective method respectively, and the compound selection is to be screened.

So the first step is to distinguish between a single item or a combination.

The implementation method is to convert the string of incoming selectors into arrays, or compound selections if the length of the array is greater than 1. If not, then determine what kind of single selector.

if (Trim (selector). Split (""). Length > 1) {The//trim () method is used to remove the blank//composite selector code at the beginning and end of the string
}//To
determine what kind of single selector 

The second step is to determine which single selector is, and then filter to return the first element.

① judge, there are two ways:

• Method One: use regular expressions.

if (/# (?: [\w\u00c0-\uffff\-]|\\.) +)/.test (selector)) {
  //id selector
}
if (/^ (?: [\w\u00c0-\uffff\-]|\\.) +)/.test (selector)) {
  //tag selector
}
if (/\. ( (?: [\w\u00c0-\uffff\-]|\\.) +)/.test (selector)) {
  //class selector
}
if (/^\[[a-za-z0-9_-\s]+\]$/.test (selector)) {
 //property Selector
}

• Method Two: Check the first character of the incoming selector

var Type=trim (selector). charAt (0);
Switch (type) {case
 ".":
  //class Selector case
 "#":
  //id Selector case
 "[":
  //Property selector
 Default :
  //tag Selector
}

② filters according to the selector.

ID and tag can be used directly using the DOM method.
class Document.getelementsbyclassname have compatibility issues and need to be defined for IE methods.
• The property selector needs to traverse all the DOM node objects and select the eligible.

ID selector return document.getElementById (Selector.slice (1,selector.length));
Tag Selector return document.getElementsByTagName (selector) [0]; Class selector if (Document.getelementsbyclassname) {return document.getelementsbyclassname (Selector.slice 1,
selector.length)) [0];
 }else{var nodes = document.all? Document.all:document.getElementsByTagName (' * ');
   for (Var i=0;i<nodes.length;i++) {var classes=nodes[i].classname.split (/\s+/);
    if (Classes.indexof (Selector.slice (1))!=-1) {//indexof Incompatible, need to extend return nodes[i on the prototype];
   Break
 }}///property Selector if (/^\[[a-za-z0-9_-\s]+\]$/.test (selector)) {selector = Selector.slice (1,selector.length-1);
 var eles = document.getElementsByTagName ("*");
 selector = selector.split ("=");
 var att = selector[0];
 var value = selector[1];
   if (value) {for (var i = 0; i < eles.length i++) {if (Eles[i].getattribute (att) ==value) {return eles[i];
    }}else{for (var i = 0; i < eles.length i++) {if (Eles[i].getattribute (att)) {return eles[i];

 } 
  }
 }
}

The third step is to implement the complex selector.

• Train of thought one:

The final filtered DOM object must be one of the set of Dom objects that satisfies the last selector, so you can select the objects first and then check each of his ancestor elements to see if they match the previous layer selector and delete them if they do not match. Iteration to the most outer layer selector, the first of the remaining DOM objects is the DOM object we are looking for.

Then, if you have n selectors, you need to make a n-1 wheel filter.

Two things need to be done to check whether the ancestor element of an element is a collection of ① objects. ② examines each element in the collection of objects and deletes the DOM object that does not meet the criteria.

Define two functions to do the two things:

Recursively checks whether the ancestor object of the ele conforms to the selector
function isparent (ele,str) {
 if (!isarray (str)) {  //If not array
  str = ToArray (str); Convert array
 }
 if (ele.parentnode) {
  if (Str.indexof (Ele.parentnode) >-1) {return
   true;
  } else{return
   isparent (ELE.PARENTNODE,STR); 
  }
 else{return
  false;
 }
Delete the Ancestor object from the Eles object
function Flitereles (eles,str) {
 if (!isarray (eles)) {
   eles = ToArray (eles);
 } For
 (var i = 0,len=eles.length;i<len; i++) {
  if (!isparent (ELES[I],STR)) {
   eles.splice (i,1);
   i = i-1;
  }
 return eles;
}

The implementation will have a bug, that is, when HTML is the following, he will filter out the "first", but it is not what we expect.

Although it is rare in practical applications to define the same class name for the parent element and child element, we cannot ignore the existence of the bug.

The performance of this implementation is also poor, because when he examines whether an object's ancestor element in an object collection conforms to a selector, he examines his parent element first, and then examines the parent element of his parent element until the parent element is not satisfied. Then he also needs to check if the next selector is met, so he goes through his parent element again. There are repeated visits to places here.

All code of thought one:

A method function GetElements (selector) {//class selector that can select all elements is required, returning all items if (/\. (?: [\w\u00c0-\uffff\-]|\\.) +)/.test (selector)) {if (document.getelementsbyclassname) {return document.getelementsbyclassname Selector.slice (1
  , selector.length)); var nodes = document.all?
  Document.all:document.getElementsByTagName (' * '); var arr=[];
    Used to save compliant classname for (Var i=0;i<nodes.length;i++) {if (Hasclass (Nodes[i],selector.slice (1,selector.length)) {
   Arr.push (Nodes[i]);
 } return arr; //id selector if (/#: [\w\u00c0-\uffff\-]|\\.)
 +)/.test (selector)) {return document.getElementById (Selector.slice (1,selector.length)); //tag selector if (/^: [\w\u00c0-\uffff\-]|\\.)
 +)/.test (selector)) {return document.getelementsbytagname (selector);
  }//Property selector if (/^\[[a-za-z0-9_-\s]+\]$/.test (selector)) {selector = Selector.slice (1,selector.length-1);
  var eles = document.getElementsByTagName ("*");
  selector = selector.split ("=");
  var att = selector[0]; var value = selector[1]; 
  var arr = []; if (value) {for (var i = 0; i < eles.length i++) {if (Eles[i].getattribute (att) ==value) {Arr.push (eles[i)
    );
    }}else{for (var i = 0; i < eles.length i++) {if (Eles[i].getattribute (att)) {Arr.push (eles[i));
 }} return arr;
 Check to see if the ancestor object of the ele conforms to the selector function isparent (ELE,STR) {if (!isarray (str)) {str = ToArray (str);
  } if (Ele.parentnode) {if (Str.indexof (Ele.parentnode) >-1) {return true; 
  }else{return isparent (ELE.PARENTNODE,STR);
 }}else{return false;
 Delete the Ancestor object from the Eles object function Flitereles (ELES,STR) {if (!isarray (eles)) {eles = ToArray (eles);
   for (var i = 0; i < eles.length i++) {if (!isparent (ELES[I],STR)) {eles.splice (i,1);
  i = i-1;
} return eles;
 }//dom element selector function $ (selector) {if (!typeof selector = = "string") {return false;
  ///Composite Selector if (Trim (selector). Split (""). Length > 1) {var all = Trim (selector). Split (""); var ELes = getelements (all[all.length-1]); for (var i = 2; i < all.length+2 && all.length-i >=0; i++) {eles = Flitereles (eles,getelements (all[all.le
  Ngth-i]));
 return eles[0]; //id selector if (/#: [\w\u00c0-\uffff\-]|\\.)
 +)/.test (selector)) {return document.getElementById (Selector.slice (1,selector.length)); The//tag selector returns only the first if ((?: [\w\u00c0-\uffff\-]|\\.)/^.
 +)/.test (selector)) {return document.getElementsByTagName (selector) [0]; }//Class selector if (/\. (?: [\w\u00c0-\uffff\-]|\\.) +)/.test (selector)) {if (document.getelementsbyclassname) {return document.getelementsbyclassname Selector.slice (1
  , selector.length)) [0]; var nodes = document.all?
  Document.all:document.getElementsByTagName (' * ');
   for (Var i=0;i<nodes.length;i++) {if (Hasclass (Nodes[i],selector.slice (1,selector.length))} {return nodes[i];
  }}///property Selector if (/^\[[a-za-z0-9_-\s]+\]$/.test (selector)) {selector = Selector.slice (1,selector.length-1); var eles = Document.getElementsbytagname ("*");
  selector = selector.split ("=");
  var att = selector[0];
  var value = selector[1];
    if (value) {for (var i = 0; i < eles.length i++) {if (Eles[i].getattribute (att) ==value) {return eles[i]; 
    }}else{for (var i = 0; i < eles.length i++) {if (Eles[i].getattribute (att)) {return eles[i];

 } 
   }
  }
 }
}

• Train of thought two:

Sift from the outermost layer to the inside.

Select the object set that conforms to the outermost selector first from document, and the target object must be the descendant element of an object of this set of objects.

So, iterate through each element of the object set, select the set of objects that match the second selector, and then traverse the new set of objects.

Until the last selector is filtered, the first object in the remaining set of objects is the target object.

This method does not need to distinguish between the match selector and the single selector, nor does it need to redefine the method of obtaining all the elements.

function $ (selector) {var all=selector.split (/\s+/);
 var result = [],rooot=[document];
  for (var i = 0; i < all.length i++) {var type=all[i][0]; Switch (type) {//id case ' # ': for (var j = 0; J < Rooot.length; J + +) {var Ele=rooot[j].getelementbyid (all[i
    ].slice (1));
    if (ele) {Result.push (ele);
  
  }} break; Class case ".": for (var j = 0; J < Rooot.length; J +) {if (document.getelementsbyclassname) {var ele
     S=rooot[j].getelementsbyclassname (All[i].slice (1));
     if (eles) {Result=result.concat (Array.prototype.slice.call (eles));
     }}else{var arr = rooot[j].getelementsbytagname ("*");
      for (var i = 0; i < arr.length i++) {if (Hasclass (arr[i), className)) {Result.push (arr[i));
  Break in}}};
   Property Case "[": var att = all[i].slice (1,all[i].length-1). Split ("=");
   var key = att[0],value=att[1]; for (var j = 0; J < Rooot.length; J + +) {var eles=Rooot[j].getelementsbytagname ("*"); for (var i = 0; i < eles.length. i++) {if (value) {for (var i = 0; i < eles.length; i++) {if El
       Es[i].getattribute (key) ==value) {Result.push (eles[i]); }}else{for (var i = 0; i < eles.length i++) {if (Eles[i].getattribute (key)) {Resul
       T.push (Eles[i]);
  The break is in}}}};
    Tag Default:for (var j = 0; J < Rooot.length; J + +) {Eles=rooot[j].getelementsbytagname (all[i));
    if (eles) {Result=result.concat (Array.prototype.slice.call (eles));
  }}}//switch Rooot=result; 
 Result=[];
}//for return rooot[0];

 }

Common methods to use:

Ie9-does not support an array of indexof ()
if (! Array.prototype.indexOf) {
 array.prototype.indexof=function (value) {for
  (var i = 0,len=this.length;i<len ; i++) {
   if (this[i]==value) {return
    i;
   }
  }
  return-1;}

Check if Ele has className
function hasclass (ele,classname) {
 if (ele&&ele.classname) {
  var classes =ele.classname.split (/\s+/);//This must be cut into an array before judging
  if (Classes.indexof (className)!=-1) {return
   true;
  } 
 } return
 false;
}

Determines whether arr is an array, returns a bool value
function IsArray (arr) {return
 Array.isarray (arr) | | Object.prototype.toString.call (arr) = = "[Object Array]";
}

The removal of whitespace characters from the string, including full-width spaces, tab, and so on, returns a string
function trim (str) {return
 str.replace (/^[\s\ufeff\xa0]+|[ \s\ufeff\xa0]+$/g, "")
}

//Convert an array of classes to a group
function ToArray (obj) {
 if (Obj.nodetype = 1) {
  return [obj];
 }
 var arr = [];
 for (var i = 0; i < obj.length i++) {
  arr.push (obj[i]);
 return arr;
}

Reference:

Https://github.com/baidu-ife/ife/blob/master/2015_spring/task/task0002/review/demo/js/util_demo.js
Https://github.com/starkwang/ife/blob/master/task/task0002/work/starkwang/js/util.js

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.