目的:
根据传入的选择器类型选出第一个符合的DOM对象。
①可以通过id获取DOM对象,例如 $("#adom");
②可以通过tagName获取DOM对象,例如 $("a");
③可以通过样式名称获取DOM对象,例如 $(".classa");
④可以通过attribute匹配获取DOM对象,例如 $("[data-log]"),$("[data-time=2015]");
⑤可以通过层叠组合获取DOM对象,例如 $("#adom .classa");
思路:
需要区分复合选择还是单项选择,单项选择的话分别用各自的方法进行获取,复合选择的话就要进行筛选。
所以第一步,区分是单项还是组合。
实现方法是将传入选择器的字符串转换成数组,如果数组长度大于1的话,就是复合选择。如果不是的话,再判断是哪一种单项选择器。
if(trim(selector).split(" ").length > 1){ //trim()方法用于去除字符串开头和结尾的空白 //复合选择器代码 } //判断是哪一种单项选择器
第二步,判断是哪一种单项选择器,然后进行筛选返回第一个元素。
①判断,有两种方法:
"htmlcode">
if(/#(("htmlcode">var type=trim(selector).charAt(0); switch(type){ case ".": //class选择器 case "#": //id选择器 case "[": //属性选择器 default: //tag选择器 }②根据选择器进行筛选。
"htmlcode">
//ID选择器 return document.getElementById(selector.slice(1,selector.length)); //tag选择器 return document.getElementsByTagName(selector)[0]; //类选择器 if(document.getElementsByClassName){ return document.getElementsByClassName(selector.slice(1,selector.length))[0]; }else{ var nodes = document.all "*"); 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]; } } } }第三步,实现复杂选择器。
"htmlcode">
//递归检查ele的祖先对象是否符合选择器 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; } } //从eles中删掉祖先对象不符合选择器的对象 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; }这个实现会有一个BUG,就是当HTML是下面这样的时候,他会筛选出“第一个”,然而它并不是我们期待的。
虽然实际应用中很少会这样给父元素和子元素定义相同的class名,但我们不能忽略这个BUG的存在。
这个实现的性能也是很差的,因为当他检查对象集合中的一个对象的祖先元素是否符合一个选择器时,他先检查他的父元素,不满足的话再检查他父元素的父元素,一直到没有父元素为止。然后他还需要检查是否符合下一个选择器,这样他又遍历了一遍他的父元素。这里有重复访问的地方。
思路一的所有代码:
//需要一个可以选择所有元素的方法 function getElements(selector){ //类选择器,返回全部项 if(/\.(("*"); 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; } } //检查ele的祖先对象是否符合选择器 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; } } //从eles中删掉祖先对象不符合选择器的对象 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元素选择器 function $(selector){ if(!typeof selector === "string"){ return false; } //复合选择器 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.length-i])); } return eles[0]; } //ID选择器 if(/#(("*"); 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]; } } } } }"htmlcode">
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 eles=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; //属性 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(eles[i].getAttribute(key)==value){ result.push(eles[i]); } } }else{ for (var i = 0; i < eles.length; i++) { if(eles[i].getAttribute(key)){ result.push(eles[i]); } } } } } break; //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]; }用到的公共方法:
//IE9-不支持数组的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; }; } //检查ele是否有className function hasClass(ele,className){ if (ele&&ele.className) { var classes=ele.className.split(/\s+/);//这里必须要切成数组之后再判断 if(classes.indexOf(className)!=-1){ return true; } } return false; } // 判断arr是否为一个数组,返回一个bool值 function isArray(arr){ return Array.isArray(arr)||Object.prototype.toString.call(arr) === "[object Array]"; } // 对字符串头尾进行空格字符的去除、包括全角半角空格、Tab等,返回一个字符串 function trim(str){ return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"") } //把一个类数组转换成数组 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; }参考:
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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
js,DOM对象选择器
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。