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 import css实例代码
Jul 18 Javascript
JavaScript Title、alt提示(Tips)实现源码解读
Dec 12 Javascript
2012年开发人员的16款新鲜的jquery插件体验分享
Dec 28 Javascript
Jqgrid设置全选(选择)及获取选择行的值示例代码
Dec 28 Javascript
JS替换文本域内的回车示例
Feb 18 Javascript
jQuery实现移动 和 渐变特效的点击事件
Feb 26 Javascript
JavaScript中的对象与JSON
Jul 03 Javascript
JS实现兼容性好,带缓冲的动感网页右键菜单效果
Sep 18 Javascript
jQuery操作Table技巧大汇总
Jan 23 Javascript
BootStrap点击下拉菜单项后显示一个新的输入框实现代码
May 16 Javascript
vue 指定组件缓存实例详解
Apr 01 Javascript
vue实现简单的登录弹出框
Oct 26 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获取数组最大值下标的方法
2015/05/12 PHP
判断、添加和删除WordPress置顶文章的相关PHP函数小结
2015/12/10 PHP
关于扩展 Laravel 默认 Session 中间件导致的 Session 写入失效问题分析
2016/01/08 PHP
window.location.hash 属性使用说明
2010/03/20 Javascript
jQuery布局插件UI Layout简介及使用方法
2013/04/03 Javascript
javaScript(JS)替换节点实现思路介绍
2013/04/17 Javascript
全屏滚动插件fullPage.js使用实例解析
2016/10/21 Javascript
JS简单实现点击按钮或文字显示遮罩层的方法
2017/04/27 Javascript
AngularJS基于provider实现全局变量的读取和赋值方法
2017/06/28 Javascript
JS实现中文汉字按拼音排序的方法
2017/10/09 Javascript
前端必备插件之纯原生JS的瀑布流插件Macy.js
2017/11/22 Javascript
详解vue-cli之webpack3构建全面提速优化
2017/12/25 Javascript
利用Decorator如何控制Koa路由详解
2018/06/26 Javascript
vue--vuex详解
2019/04/15 Javascript
keep-Alive搭配vue-router实现缓存页面效果的示例代码
2020/06/24 Javascript
[36:02]DOTA2上海特级锦标赛D组小组赛#2 Liquid VS VP第一局
2016/02/28 DOTA
Python中的MongoDB基本操作:连接、查询实例
2015/02/13 Python
Python标准库之collections包的使用教程
2017/04/27 Python
Python利用QQ邮箱发送邮件的实现方法(分享)
2017/06/09 Python
Python 判断是否为质数或素数的实例
2017/10/30 Python
微信跳一跳小游戏python脚本
2018/01/05 Python
详解python多线程之间的同步(一)
2019/04/03 Python
Python scipy的二维图像卷积运算与图像模糊处理操作示例
2019/09/06 Python
详解Python3定时器任务代码
2019/09/23 Python
OpenCV python sklearn随机超参数搜索的实现
2020/01/17 Python
Grow Gorgeous美国官网:只要八天,体验唤醒毛囊后新生的茂密秀发
2018/06/04 全球购物
Abbott Lyon官网:女士手表、珠宝及配件
2020/12/26 全球购物
大二自我鉴定范文
2013/10/05 职场文书
教师竞聘演讲稿
2014/05/16 职场文书
销售目标责任书
2014/07/23 职场文书
清明节网上祭英烈寄语2015
2015/03/04 职场文书
小学生2015教师节演讲稿
2015/03/19 职场文书
听证通知书
2015/04/24 职场文书
2015年法律事务部工作总结
2015/07/27 职场文书
Nginx访问日志及错误日志参数说明
2021/03/31 Servers
大脑的记忆过程在做数据压缩,不同图形也有共同的记忆格式
2022/04/29 数码科技