相思资源网 Design By www.200059.com
解释器模式(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));
开放封闭原则:面向对象中的开放封闭原则是类或模块应该对扩展开放对修改封闭,在这个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));
标签:
DOM,选择器
相思资源网 Design By www.200059.com
广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
相思资源网 Design By www.200059.com
暂无JavaScript实现自己的DOM选择器原理及代码的评论...
稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!
昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。
这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。
而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?