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 基于原型的对象(创建、调用)
Oct 16 Javascript
理解JAVASCRIPT中hasOwnProperty()的作用
Jun 05 Javascript
JavaScript对数组进行随机重排的方法
Jul 22 Javascript
JS+CSS实现仿msn风格选项卡效果代码
Oct 22 Javascript
jquery实现九宫格大转盘抽奖
Nov 13 Javascript
js eval函数使用,js对象和字符串互转实例
Mar 06 Javascript
jQuery实现扑克正反面翻牌效果
Mar 10 Javascript
详解如何在Vue2中实现组件props双向绑定
Mar 29 Javascript
微信小程序Getuserinfo解决方案图解
Aug 24 Javascript
Node.js学习教程之Module模块
Sep 03 Javascript
vue使用echarts实现折线图
Mar 21 Vue.js
vue使用watch监听属性变化
Apr 30 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从FLV文件获取视频预览图的方法
2015/03/12 PHP
PHP面向对象程序设计实例分析
2016/01/26 PHP
php中static和const关键字用法分析
2016/12/07 PHP
Javascript的一种模块模式
2010/09/08 Javascript
js创建数据共享接口——简化框架之间相互传值
2011/10/23 Javascript
JS打开新窗口的2种方式
2013/04/18 Javascript
浅谈JavaScript数据类型
2015/03/03 Javascript
JS实现网页每隔3秒弹出一次对话框的方法
2015/11/09 Javascript
jquery popupDialog 使用 加载jsp页面的方法
2016/10/25 Javascript
JS实现全屏的四种写法
2016/12/30 Javascript
Bootstrap 中data-[*] 属性的整理
2018/03/13 Javascript
详解如何用babel转换es6的class语法
2018/04/03 Javascript
VUE搭建手机商城心得和遇到的坑
2019/02/21 Javascript
浅析JavaScript异步代码优化
2019/03/18 Javascript
一文了解vue-router之hash模式和history模式
2019/05/31 Javascript
微信小程序页面滚动到指定位置代码实例
2019/09/07 Javascript
JavaScript 生成唯一ID的几种方式
2021/02/19 Javascript
详细解析Python中__init__()方法的高级应用
2015/05/11 Python
Python 正则表达式入门(初级篇)
2016/12/07 Python
CentOS 7下安装Python 3.5并与Python2.7兼容并存详解
2017/07/07 Python
TensorFlow 模型载入方法汇总(小结)
2018/06/19 Python
我喜欢你 抖音表白程序python版
2019/04/07 Python
django-orm F对象的使用 按照两个字段的和,乘积排序实例
2020/05/18 Python
Python3读写ini配置文件的示例
2020/11/06 Python
canvas基础之图形验证码的示例
2018/01/02 HTML / CSS
罗马尼亚购物网站:Vivantis.ro
2019/07/20 全球购物
Made in Design英国:设计家具、照明、家庭装饰和花园家具
2019/09/24 全球购物
用Python匹配HTML tag的时候,<.*>和<.*?>有什么区别
2012/11/04 面试题
《最佳路径》教学反思
2014/04/13 职场文书
程序员求职信
2014/04/16 职场文书
高一学生评语大全
2014/04/25 职场文书
正风肃纪查摆剖析材料
2014/10/10 职场文书
学生逃课检讨书1000字
2014/10/20 职场文书
受资助学生感谢信
2015/01/21 职场文书
药品销售内勤岗位职责
2015/04/13 职场文书
解决Nginx 配置 proxy_pass 后 返回404问题
2021/03/31 Servers