匹配元素用JavaScript实现自己的DOM选择器

上班之余抽点时间出来写写博文,希望对新接触的朋友有帮助。今天在这里和大家一起学习一下匹配元素

    解释器模式(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));

文章结束给大家分享下程序员的一些笑话语录: PC软件体积大,是因为一个PC软件功能往往较多,能够满足你一个方面的需求,而一个iphone软件往往没几行代码,干一件很小的事情,自然需要的软件就多。就像吃西瓜和吃瓜子的来比数目,单位不同啊。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值