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 相关文章推荐
控制input输入框中提示信息的显示和隐藏的方法
Feb 12 Javascript
通过原生JS实现为元素添加事件的方法
Nov 23 Javascript
浅析jQuery操作select控件的取值和设值
Dec 07 Javascript
Ajax实现不刷新取最新商品
Mar 01 Javascript
微信小程序实现锚点定位楼层跳跃的实例
May 18 Javascript
微信小程序实现发送模板消息功能示例【通过openid推送消息给用户】
May 05 Javascript
微信小程序的授权实现过程解析
Aug 02 Javascript
vue 实现强制类型转换 数字类型转为字符串
Nov 07 Javascript
vue实现页面内容禁止选中功能,仅输入框和文本域可选
Nov 09 Javascript
vue实现购物车案例
May 30 Javascript
微信小程序实现搜索框功能及踩过的坑
Jun 19 Javascript
vue实现在data里引入相对路径
Jun 05 Vue.js
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/10/09 PHP
来自phpguru得Php Cache类源码
2010/04/15 PHP
用php实现百度网盘图片直链的代码分享
2012/11/01 PHP
php快速排序原理与实现方法分析
2016/05/26 PHP
PHP常用操作类之通信数据封装类的实现
2017/07/16 PHP
用脚本调用样式的几种方法
2006/12/09 Javascript
js与运算符和或运算符的妙用
2014/02/14 Javascript
JS跨域问题详解
2014/11/25 Javascript
jquery实现图片上传之前预览的方法
2015/07/11 Javascript
基于JavaScript实现生成名片、链接等二维码
2015/09/20 Javascript
JavaScript中的数据类型转换方法小结
2015/10/26 Javascript
JS实现的自定义水平滚动字体插件完整实例
2016/06/17 Javascript
Google 地图API Map()构造器详解
2016/08/06 Javascript
完美解决jQuery符号$与其他javascript 库、框架冲突的问题
2016/08/09 Javascript
Vue.js双向绑定操作技巧(初级入门)
2016/12/27 Javascript
深入理解node.js之path模块
2017/05/03 Javascript
jQuery复合事件结合toggle()方法的用法示例
2017/06/10 jQuery
JsChart组件使用详解
2018/03/04 Javascript
vue多页面开发和打包正确处理方法
2018/04/20 Javascript
浅谈对于“不用setInterval,用setTimeout”的理解
2019/08/28 Javascript
vue 使用 vue-pdf 实现pdf在线预览的示例代码
2020/04/26 Javascript
[53:52]OG vs EG 2018国际邀请赛淘汰赛BO3 第二场 8.23
2018/08/24 DOTA
win10下Python3.6安装、配置以及pip安装包教程
2017/10/01 Python
对Python中DataFrame按照行遍历的方法
2018/04/08 Python
python实现输入任意一个大写字母生成金字塔的示例
2019/10/27 Python
python读取图片的几种方式及图像宽和高的存储顺序
2020/02/11 Python
sklearn的predict_proba使用说明
2020/06/28 Python
python dict如何定义
2020/09/02 Python
YOINS官网:时尚女装网上购物
2017/03/17 全球购物
初婚未育未抱养证明
2014/01/12 职场文书
商务英语专业求职信范文
2014/01/28 职场文书
省优秀教师事迹材料
2014/01/30 职场文书
运输企业安全生产责任书
2014/07/28 职场文书
党的群众路线教育实践活动领导班子对照检查材料
2014/09/25 职场文书
团党委领导干部党的群众路线教育实践活动个人对照检查材料思想汇
2014/10/05 职场文书
承诺书怎么写 ?
2019/04/16 职场文书