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 相关文章推荐
javascript算法题 求任意一个1-9位不重复的N位数在该组合中的大小排列序号
Jul 21 Javascript
探讨js中的双感叹号判断
Nov 11 Javascript
JSON无限折叠菜单编写实例
Dec 16 Javascript
js动态创建上传表单通过iframe模拟Ajax实现无刷新
Feb 20 Javascript
node.js中的fs.open方法使用说明
Dec 17 Javascript
浅谈jQuery为哪般去掉了浏览器检测
Aug 29 Javascript
jQuery插件FusionCharts绘制的2D双柱状图效果示例【附demo源码】
May 13 jQuery
jQuery层级选择器_动力节点节点Java学院整理
Jul 04 jQuery
Vue导出页面为PDF格式的实现思路
Jul 31 Javascript
jQuery实现的简单日历组件定义与用法示例
Dec 24 jQuery
使用JavaScript获取扫码枪扫描得到的条形码的思路代码详解
Jun 10 Javascript
解决ant Design中Select设置initialValue时的大坑
Oct 29 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
剖析 PHP 中的输出缓冲
2006/12/21 PHP
php实现的微信红包算法分析(非官方)
2015/09/25 PHP
PHP+MariaDB数据库操作基本技巧备忘总结
2018/05/21 PHP
10款新鲜出炉的 jQuery 插件(Ajax 插件,有幻灯片、图片画廊、菜单等)
2011/06/08 Javascript
jquery入门—选择器实现隔行变色实例代码
2013/01/04 Javascript
JS的document.all函数使用示例
2013/12/30 Javascript
Javascript遍历Html Table示例(包括内容和属性值)
2014/07/08 Javascript
html、css和jquery相结合实现简单的进度条效果实例代码
2016/10/24 Javascript
jQuery 移动端拖拽(模块化开发,触摸事件,webpack)
2016/10/28 Javascript
jQuery实现checkbox列表的全选、反选功能
2016/11/24 Javascript
AngularJS实现用户登录状态判断的方法(Model添加拦截过滤器,路由增加限制)
2016/12/12 Javascript
Angular ng-repeat遍历渲染完页面后执行其他操作详细介绍
2016/12/13 Javascript
nodejs和php实现图片访问实时处理
2017/01/05 NodeJs
vue之nextTick全面解析
2017/05/17 Javascript
深入理解Vuex 模块化(module)
2017/09/26 Javascript
Vue加载组件、动态加载组件的几种方式
2018/08/31 Javascript
总结4个方面优化Vue项目
2019/02/11 Javascript
浅谈Express.js解析Post数据类型的正确姿势
2019/05/30 Javascript
Vue基础学习之项目整合及优化
2019/06/02 Javascript
Array.filter中如何正确使用Async
2020/11/04 Javascript
Python脚本在Appium库上对移动应用实现自动化测试
2015/04/17 Python
使用python检测主机存活端口及检查存活主机
2015/10/12 Python
详解python开发环境搭建
2016/12/16 Python
python cx_Oracle模块的安装和使用详细介绍
2017/02/13 Python
Python列表推导式、字典推导式与集合推导式用法实例分析
2018/02/07 Python
Python面向对象之静态属性、类方法与静态方法分析
2018/08/24 Python
pandas 时间格式转换的实现
2019/07/06 Python
英国最大的在线运动补充剂商店:Discount Supplements
2017/06/03 全球购物
优秀团员个人的自我评价
2013/10/02 职场文书
军校本科大学生自我评价
2014/01/14 职场文书
决心书范文
2014/03/11 职场文书
函授生自我鉴定
2014/03/25 职场文书
活动总结范文
2014/08/30 职场文书
民主评议党员自我评价材料
2014/09/18 职场文书
JS ES6异步解决方案
2021/04/29 Javascript
JS开发前端团队展示控制器来为成员引流
2022/08/14 Javascript