JavaScript实现自己的DOM选择器原理及代码


Posted in Javascript onMarch 04, 2013

解释器模式(Interpreter):定义一种语法格式,通过程序解释执行它并完成相应的任务。在前端编程场景中可以应用解释器模式来解释CSS选择符实现DOM元素的选择。

开放封闭原则:面向对象中的开放封闭原则是类或模块应该对扩展开放对修改封闭,在这个dom选择器中实现id选择器,元素选择器,类选择器,如果以后需要属性选择器的话定义一个属性选择器实现相应的方法,同时在简单工厂中增加相应的创建属性选择器对象分支即可。

匹配原理:浏览器在匹配CSS选择符时是按照从右到左匹配的,所以实现自己的DOM选择器时匹配行为也应该和浏览原生匹配行为一致。

代码:

(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; 
//调用原生选择器 
if(!simple.test(query) && context.querySelectorAll){ 
return context.querySelectorAll(query); 
}else { 
//调用自定义选择器 
return interpret(query, context); 
} 
} 
//解释执行dom选择符 
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选择器 
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); 
}; 
//元素选择器 
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); 
}; 
//类选择器 
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 || "*")); 
//支持原生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:属性选择器 
function AttributeSelector(attr){ 
this.find = function(context){ 
}; 
this.match = function(element){ 
}; 
} 
AttributeSelector.test = function (selector){ 
var regex = /\[([\w\-_]+)(?:=([\w\-_]+))?\]/; 
return regex.test(selector); 
}; 
//根据父级元素过滤 
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; 
} 
//根据查询选择符创建相应选择器对象 
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));
Javascript 相关文章推荐
利用js实现选项卡的特别效果的实例
Mar 03 Javascript
jQuery探测位置的提示弹窗(toolTip box)详细解析
Nov 14 Javascript
jquery交替变换颜色的三种方法 实例代码
Nov 19 Javascript
对比分析AngularJS中的$http.post与jQuery.post的区别
Feb 27 Javascript
javascript实现点击后变换按钮显示文字的方法
May 13 Javascript
JavaScript的面向对象编程基础
Aug 13 Javascript
js完整倒计时代码分享
Sep 18 Javascript
javascript简写常用的12个技巧(可以大大减少你的js代码量)
Mar 28 Javascript
angular4 JavaScript内存溢出问题
Mar 06 Javascript
Vue利用canvas实现移动端手写板的方法
May 03 Javascript
layer.confirm取消按钮绑定事件的方法
Aug 17 Javascript
解决微信小程序防止无法回到主页的问题
Sep 28 Javascript
jQuery:节点(插入,复制,替换,删除)操作
Mar 04 #Javascript
JS获取后台Cookies值的小例子
Mar 04 #Javascript
JQuery获取各种宽度、高度(format函数)实例
Mar 04 #Javascript
javascript加号&quot;+&quot;的二义性说明
Mar 04 #Javascript
js给dropdownlist添加选项的小例子
Mar 04 #Javascript
jQuery侧边栏随窗口滚动实现方法
Mar 04 #Javascript
利用js实现选项卡的特别效果的实例
Mar 03 #Javascript
You might like
DC这些乐高系列动画电影你看过几部?
2020/04/09 欧美动漫
php flush类输出缓冲剖析
2008/10/19 PHP
apache和php之间协同工作的配置经验分享
2013/04/08 PHP
php fread读取文件注意事项
2016/09/24 PHP
Javascript技术技巧大全(五)
2007/01/22 Javascript
javascript下function声明一些小结
2007/12/28 Javascript
js特效,页面下雪的小例子
2013/06/17 Javascript
用javascript删除当前行,添加行(示例代码)
2013/11/25 Javascript
Javascript中call的两种用法实例
2013/12/13 Javascript
node.js+Ajax实现获取HTTP服务器返回数据
2014/11/26 Javascript
javascript基本包装类型介绍
2015/04/10 Javascript
Javascript实现获取及设置光标位置的方法
2015/07/21 Javascript
jquery SweetAlert插件实现响应式提示框
2015/08/18 Javascript
angularJS Provider、factory、service详解及实例代码
2016/09/21 Javascript
react实现一个优雅的图片占位模块组件详解
2017/10/30 Javascript
关于HTTP传输中gzip压缩的秘密探索分析
2018/01/12 Javascript
Bootstrap popover 实现鼠标移入移除显示隐藏功能方法
2018/01/24 Javascript
微信小程序修改swiper默认指示器样式的实例代码
2018/07/18 Javascript
js简单实现自动生成表格功能示例
2020/06/02 Javascript
vue实现PC端分辨率适配操作
2020/08/03 Javascript
JavaScript实现缓动动画
2020/11/25 Javascript
Python实现的几个常用排序算法实例
2014/06/16 Python
Python警察与小偷的实现之一客户端与服务端通信实例
2014/10/09 Python
Python单元测试框架unittest简明使用实例
2015/04/13 Python
使用python 和 lint 删除项目无用资源的方法
2017/12/20 Python
Python 经典面试题 21 道【不可错过】
2018/09/21 Python
python制作填词游戏步骤详解
2019/05/05 Python
python按键按住不放持续响应的实例代码
2019/07/17 Python
python多线程分块读取文件
2019/08/29 Python
基于css3实现漂亮便签样式
2013/03/18 HTML / CSS
canvas实现有递增动画的环形进度条的实现方法
2019/07/10 HTML / CSS
Html5无刷新修改browser Url的方法
2014/01/15 HTML / CSS
英国领先的在线药房:Pharmacy First
2017/09/10 全球购物
2014年圣诞节促销方案
2014/03/14 职场文书
大学英语专业求职信
2014/06/21 职场文书
MySQL基础快速入门知识总结(附思维导图)
2021/09/25 MySQL