在上篇介绍了选择器的获取标签、id、类名的方法,现在我们在上篇基础上继续升级

1、问题描述:上篇get('选择器')已经实现,如果get方法里是一个选择器的父元素,父元素是DOM对象,那么如何获取元素

思路:1、首先想到的是标签、id、类名的三个方法  2、假设是body节点,那么方法中的document改成body 3、传入的参数如何判断是否为DOM

注意:在获取id方法中全局也只有一个id,所以其中的doument无须修改

修改如下

// 注释: 对获取DOM对象方法的封装
var getTag = function ( tag, context, results ) {
results = results || [];
context = context || document;//防止context是空时报错现象出现 results.push.apply( results, context.getElementsByTagName( tag ) );
return results;
}; var getId = function ( id, results ) {
results = results || [];
results.push( document.getElementById( id ) );
return results;
}; var getClass = function ( className, context, results ) {
results = results || [];
context = context || document;
if ( document.getElementsByClassName ) {
results.push.apply( results, context.getElementsByClassName( className ) );
} else {
each( getTag( '*', context ), function ( i, v ) {
if ( ( ' ' + v.className + ' ' )
.indexOf( ' ' + className + ' ' ) != -1 ) {
results.push( v );
}
} );
}
return results;
}; // 对each方法的封装
var each = function ( arr, fn ) {
for ( var i = 0; i < arr.length; i++ ) {
if ( fn.call( arr[ i ], i, arr[ i ] ) === false ) {
break;
}
}
}; // 通用的get方法
var get = function ( selector, context, results ) {
results = results || [];
var rquickExpr = /^(?:#([\w-]+)|\.([\w-]+)|([\w]+)|(\*))$/,
m = rquickExpr.exec( selector ); if ( m ) {
if ( m[ 1 ] ) {
results = getId( m[ 1 ], results );
} else if ( m[ 2 ] ) {
results = getClass( m[ 2 ], context, results );
} else if ( m[ 3 ] ) {
results = getTag( m[ 3 ], context, results );
} else if ( m[ 4 ] ) {
results = getTag( m[ 4 ], context, results );
} }

验证以上封装的方法,html如下(为了使用方便,以下封装的js都单独放在common.js文件中,在html中须引入使用)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
.rect {
width: 400px;
height: 50px;
margin: 10px 0;
}
.c { border: 1px dashed red; }
.c1 { border: 1px dashed green; }
.c2 { border: 1px dashed blue; }
</style>
<script src="common.js"></script>//把上面的函数单独放在一个js文件中,在html中引入
</head>
<body>
<div class="c">
<div class="c1 rect"></div>
<div class="c2 rect"></div>
<div class="c1 rect"></div>
<div class="c2 rect"></div>
</div>
<hr />
<div>
<div class="c1 rect"></div>
<div class="c2 rect"></div>
<div class="c1 rect"></div>
<div class="c2 rect"></div>
</div>
</body>
<script type="text/javascript">
get( '.c1', get( '.c' )[ 0 ] )[ 1]
.style.backgroundColor = 'lightgreen'; </script>
</html>

2、问题描述:假设get方法中传入的context是一个DOM数组
思路:首先想到需要遍历数组,那么问题来了,如何判断是否为DOM数组,如果不是数组怎么办,还有在哪一个方法中遍历呢

// 注释: 对基本DOM数组方法的封装
var getTag = function ( tag, context, results ) {
results = results || [];
results.push.apply( results, context.getElementsByTagName( tag ) );
return results;
}; var getId = function ( id, results ) {
results = results || [];
results.push( document.getElementById( id ) );
return results;
}; var getClass = function ( className, context, results ) {
results = results || []; if ( document.getElementsByClassName ) {
results.push.apply( results, context.getElementsByClassName( className ) );
} else {
each( getTag( '*', context ), function ( i, v ) {
if ( ( ' ' + v.className + ' ' )
.indexOf( ' ' + className + ' ' ) != -1 ) {
results.push( v );
}
} );
}
return results;
}; // 对each方法的封装
var each = function ( arr, fn ) {
for ( var i = 0; i < arr.length; i++ ) {
if ( fn.call( arr[ i ], i, arr[ i ] ) === false ) {
break;
}
}
}; // 通用的方法
var get = function ( selector, context, results ) {
results = results || [];
context = context || document;
// 1 2 3 4
var rquickExpr = /^(?:#([\w-]+)|\.([\w-]+)|([\w]+)|(\*))$/,
m = rquickExpr.exec( selector ); if ( m ) {
//此处判断context是否为数组,如果不是数组让其成为数组
if ( context.nodeType ) {
context = [ context ];
}
each( context, function ( i, v ) {
if ( m[ 1 ] ) {
results = getId( m[ 1 ], results );
} else if ( m[ 2 ] ) {
results = getClass( m[ 2 ], this, results );//this可以替代v
} else if ( m[ 3 ] ) {
results = getTag( m[ 3 ], this, results );
} else if ( m[ 4 ] ) {
results = getTag( m[ 4 ], this, results );
}
} );
} return results;
};

验证以上封装的方法,html如下

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
.rect {
width: 400px;
height: 50px;
margin: 10px 0;
}
.c { border: 1px dashed red; }
.c1 { border: 1px dashed green; }
.c2 { border: 1px dashed blue; }
</style>
<script src="common.js"></script>
</head>
<body>
<div class="c">
<div class="c1 rect"></div>
<div class="c2 rect"></div>
<div class="c1 rect"></div>
<div class="c2 rect"></div>
</div>
<hr />
<div class="c">
<div class="c1 rect"></div>
<div class="c2 rect"></div>
<div class="c1 rect"></div>
<div class="c2 rect"></div>
</div>
</body>
<script type="text/javascript">
var l = get( '.c' );
each( get( '.c1', l ), function () {
this.style.backgroundColor = 'lightblue';
} );
</script>
</html>

3、问题描述:假设get方法中传入的context是一个选择器字符串,也就是在页面中找到一个节点,然后在其后代再找出符合要求的节点
思路:此时传入context是一个选择器字符串,判断其是否为字符串,现在假设先把这个字符串找出来,然后再通过each方法找出其后代的元素

var myPush = function( target, els ) {
var j = target.length,
i = 0;
// Can't trust NodeList.length
while ( (target[j++] = els[i++]) ) {}
target.length = j - 1;
}; // 注释: 对基本方法的封装
var getTag = function ( tag, context, results ) {
results = results || [];
//此处也无须用context=context||[]
try {
results.push.apply( results, context.getElementsByTagName( tag ) );//ie8及以下版本不支持传入伪数组
} catch ( e ) {
myPush( results, context.getElementsByTagName( tag ) );//对ie8及以下版本的支持
} return results;
}; var getId = function ( id, results ) {
results = results || [];
results.push( document.getElementById( id ) );
return results;
}; var getClass = function ( className, context, results ) {
results = results || []; if ( document.getElementsByClassName ) {
results.push.apply( results, context.getElementsByClassName( className ) );
} else {
each( getTag( '*', context ), function ( i, v ) {
if ( ( ' ' + v.className + ' ' )
.indexOf( ' ' + className + ' ' ) != -1 ) {
results.push( v );
}
} );
}
return results;
}; // 对each方法的封装
var each = function ( arr, fn ) {
for ( var i = 0; i < arr.length; i++ ) {
if ( fn.call( arr[ i ], i, arr[ i ] ) === false ) {
break;
}
}
}; // 通用的get方法
var get = function ( selector, context, results ) {
results = results || [];
context = context || document;
var rquickExpr = /^(?:#([\w-]+)|\.([\w-]+)|([\w]+)|(\*))$/,
m = rquickExpr.exec( selector ); if ( m ) {
if ( context.nodeType ) {
context = [ context ];
}
//此时对context判断是否为字符串,如果是假设已经找出context
if ( typeof context == 'string' ) {
context = get( context );
}
each( context, function ( i, v ) {
if ( m[ 1 ] ) {
results = getId( m[ 1 ], results );
} else if ( m[ 2 ] ) {
results = getClass( m[ 2 ], this, results );//此处可以用this,也可以用v
} else if ( m[ 3 ] ) {
results = getTag( m[ 3 ], this, results );
} else if ( m[ 4 ] ) {
results = getTag( m[ 4 ], this, results );
}
} );
} return results;
};

验证以上封装的方法,html如下

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
.rect {
width: 400px;
height: 50px;
margin: 10px 0;
}
.c {
border: 1px dashed red;
}
.c1 { border: 1px dashed green; }
.c2 { border: 1px dashed blue; }
</style> <script src="common.js"></script>
</head>
<body>
<div class="c">
<div class="c1 rect"></div>
<div class="c2 rect"></div>
<div class="c1 rect"></div>
<div class="c2 rect"></div>
</div>
<hr />
<div>
<div class="c1 rect"></div>
<div class="c2 rect"></div>
</div>
<hr />
<div class="c">
<div class="c1 rect"></div>
</div>
</body>
<script type="text/javascript">
// 在页面中找到所有的 .c 的节点, 然后在 .c 的后代元素中
// 找符合 .c1 的节点, 并返回
each( get( '.c1', '.c' ), function () {
this.style.backgroundColor = 'skyblue';
} );
</script>
</html>

4、问题描述:假设get方法中传入的context是多个选择器字符串,在这处理的是组合选择器

思路: 拿到多个选择器的字符串, 首先需要处理的是逗号,将其分解成几个简单的部分, 然后再逐一处理,每一个子选择器, 都是按照从左往右的形式去过滤,先处理一个选择器, 得到的结果再被后面的选择器进行处理

var myPush = function( target, els ) {
var j = target.length,
i = 0;
// Can't trust NodeList.length
while ( (target[j++] = els[i++]) ) {}
target.length = j - 1;
}; // 注释: 对基本方法的封装
var getTag = function ( tag, context, results ) {
results = results || [];
try {
results.push.apply( results, context.getElementsByTagName( tag ) );
} catch ( e ) {
myPush( results, context.getElementsByTagName( tag ) );
} return results;
}; var getId = function ( id, results ) {
results = results || [];
results.push( document.getElementById( id ) );
return results;
}; var getClass = function ( className, context, results ) {
results = results || []; if ( document.getElementsByClassName ) {
results.push.apply( results, context.getElementsByClassName( className ) );
} else {
each( getTag( '*', context ), function ( i, v ) {
if ( ( ' ' + v.className + ' ' )
.indexOf( ' ' + className + ' ' ) != -1 ) {
results.push( v );
}
} );
}
return results;
}; // 对each方法的封装
var each = function ( arr, fn ) {
for ( var i = 0; i < arr.length; i++ ) {
if ( fn.call( arr[ i ], i, arr[ i ] ) === false ) {
break;
}
}
}; //对myTrim方法的封装,去空格
var myTrim = function ( str ) {
if ( String.prototype.trim ) {
return str.trim();
} else {
return str.replace( /^\s+|\s+$/g, '' );
}
}; // 通用的get方法
var get = function ( selector, context, results ) {
results = results || [];
context = context || document;
// 1 2 3 4
var rquickExpr = /^(?:#([\w-]+)|\.([\w-]+)|([\w]+)|(\*))$/,
m = rquickExpr.exec( selector ); if ( m ) {
if ( context.nodeType ) {
context = [ context ];
}
// 如果 context 是一个 dom 数组就没有问题了
// 但是 context 是一个选择器字符串. 有可能是 '.c'
//
if ( typeof context == 'string' ) {
context = get( context );
}
each( context, function ( i, v ) {
if ( m[ 1 ] ) {
results = getId( m[ 1 ], results );
} else if ( m[ 2 ] ) {
results = getClass( m[ 2 ], v, results );
} else if ( m[ 3 ] ) {
results = getTag( m[ 3 ], this, results );
} else if ( m[ 4 ] ) {
results = getTag( m[ 4 ], this, results );
}
} );
} return results;
}; var select = function ( selector, context, results ) {
results = results || [];
// 首先处理逗号
var newSelectors = selector.split( ',' );
// 细节: 一般不考虑两端的空格
each( newSelectors, function ( i, v ) {
results.push.apply( results, get( myTrim( v ), context ) );
} );
//此处我们可以用for in方法进行分解
/*for(var k in newSelectors){
var v = newSelectors[k];
v = myTrim(v)//v.trim();
var list = get(v,context);
results.push.apply(results,list); }*/
return results;
};

验证以上封装的方法,html如下

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
.rect {
width: 400px;
height: 50px;
margin: 10px 0;
}
.c1 {
border: 1px dashed red;
}
.c2 { border: 1px dashed green; }
.c3 { border: 1px dashed blue; }
</style>
<script src="common.js"></script> </head>
<body>
<div class="c">
<div class="c1 rect"></div>
<div class="c2 rect"></div>
<div class="c3 rect"></div>
<div class="c2 rect"></div>
</div>
<hr />
<div>
<div class="c1 rect"></div>
<div class="c3 rect"></div>
</div>
<hr />
<div class="c">
<div class="c1 rect"></div>
</div>
</body>
<script>
var list = select( '.c1, .c2' );
each( list, function () {
this.style.backgroundColor = 'skyblue';
}); </script>
</html>

5、问题描述:在这我们传入的是后代选择器字符串

思路:假设list = get('.c  .c1',context),即在context下找出.c,然后再在.c下找出.c1

等价于:list = get('.c ',context);  list = get('.c1',list)

var myPush = function( target, els ) {
var j = target.length,
i = 0;
// Can't trust NodeList.length
while ( (target[j++] = els[i++]) ) {}
target.length = j - 1;
}; // 注释: 对基本方法的封装
var getTag = function ( tag, context, results ) {
results = results || [];
try {
results.push.apply( results, context.getElementsByTagName( tag ) );
} catch ( e ) {
myPush( results, context.getElementsByTagName( tag ) );
} return results;
}; var getId = function ( id, results ) {
results = results || [];
results.push( document.getElementById( id ) );
return results;
}; var getClass = function ( className, context, results ) {
results = results || []; if ( document.getElementsByClassName ) {
results.push.apply( results, context.getElementsByClassName( className ) );
} else {
each( getTag( '*', context ), function ( i, v ) {
if ( ( ' ' + v.className + ' ' )
.indexOf( ' ' + className + ' ' ) != -1 ) {
results.push( v );
}
} );
}
return results;
}; // 对each方法的封装
var each = function ( arr, fn ) {
for ( var i = 0; i < arr.length; i++ ) {
if ( fn.call( arr[ i ], i, arr[ i ] ) === false ) {
break;
}
}
}; //对myTrim方法的封装,去空格
var myTrim = function ( str ) {
if ( String.prototype.trim ) {
return str.trim();
} else {
return str.replace( /^\s+|\s+$/g, '' );
}
}; // 通用的get方法
var get = function ( selector, context, results ) {
results = results || [];
context = context || document;
// 1 2 3 4
var rquickExpr = /^(?:#([\w-]+)|\.([\w-]+)|([\w]+)|(\*))$/,
m = rquickExpr.exec( selector ); if ( m ) {
if ( context.nodeType ) {
context = [ context ];
}
// 如果 context 是一个 dom 数组就没有问题了
// 但是 context 是一个选择器字符串. 有可能是 '.c'
//
if ( typeof context == 'string' ) {
context = get( context );
}
each( context, function ( i, v ) {
if ( m[ 1 ] ) {
results = getId( m[ 1 ], results );
} else if ( m[ 2 ] ) {
results = getClass( m[ 2 ], v, results );
} else if ( m[ 3 ] ) {
results = getTag( m[ 3 ], this, results );
} else if ( m[ 4 ] ) {
results = getTag( m[ 4 ], this, results );
}
} );
} return results;
}; var select = function ( selector, context, results ) {
results = results || [];
// 首先处理逗号
var newSelectors = selector.split( ',' );
// 细节: 一般不考虑两端的空格
each( newSelectors, function ( i, v ) { var list = v.split(' ');
var cont = context;
for(var i = 0;i <list.length;i++){
//如果list[i]是空字符串,会生成一个新数组,则需要进行如下判断
if(list[i] === '') continue;
cont = get(list[i],cont);
}
results.push.apply( results, cont );
} ); return results;
};

验证以上封装的方法,html如下

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
.rect {
width: 400px;
height: 50px;
margin: 10px 0;
}
.c1 {
border: 1px dashed red;
}
.c2 { border: 1px dashed green; }
.c3 { border: 1px dashed blue; }
</style>
<script src="common.js"></script> </head>
<body>
<div class="c">
<div class="c1 rect"></div>
<div class="c2 rect"></div>
<div class="c3 rect"><p>123</p></div>
<div class="c2 rect"></div>
</div>
<hr />
<div>
<div class="c1 rect"></div>
<div class="c3 rect"></div>
</div>
<hr />
<div class="c">
<div class="c1 rect"></div>
</div>
</body>
<script>
var list = select( '.c .c2' );
each( list, function () {
this.style.backgroundColor = 'skyblue';
}); </script>
</html>

未完待续

关于js封装框架类库之选择器引擎(二)的更多相关文章

  1. 关于js封装框架类库之选择器引擎(一)

    选择器模块之传统做法 var tag = function (tag){ return document.getElementsByTagName(tag); } var id = function ...

  2. 关于js封装框架类库之DOM操作模块(二)

    上一篇基本实现了框架结构,但是与真正能用上的项目框架比较还是存在很多不足,在这又做了些加强与优化 (function ( window, undefined ) { var arr = [], pus ...

  3. 关于js封装框架类库之样式操作

    在js中,对样式的操作我们并不感到陌生,在很多框架中都是用极少的代码,实现更强大的功能,在这做出一些的总结.存在不足还望指出! 1.封装一个添加css的方法(这篇引用了前面的框架结构) 在 js 中 ...

  4. 关于js封装框架类库之DOM操作模块(一)

    在前端开发的过程中,javascript极为重要的一个功能就是对DOM对象的操作,而对其封装就是为了更好地进行DOM操作,提高浏览器的支持效率 现在给出一个案例:页面创建三个div,然后给其添加样式 ...

  5. 关于js封装框架类库之事件模块

    在触发DOM上的某个事件时,会产生一个事件对象event.这个对象中包含着所有与事件有关的信息.包括导致事件的元素,事件的类型以及其他与特定事件相关的信息. 例如: 鼠标操作点击事件时,事件对象中会获 ...

  6. 关于js封装框架类库之属性操作

    在对DOM对象操作时,往往都要涉及到其属性的操作,为了提高开发效率,同时兼顾浏览器的性能,在这简单的封装了几个常见的属性.因为是模块化,在这只是引入了部分代码,其他代码在前几篇模块封装中有写.如有不足 ...

  7. 【原创】使用JS封装的一个小型游戏引擎及源码分享

    1 /** * @description: 引擎的设计与实现 * @user: xiugang * @time: 2018/10/01 */ /* * V1.0: 引擎实现的基本模块思路 * 1.创建 ...

  8. JS框架设计读书笔记之-选择器引擎02

    选择器引擎涉及相关概念 概念 以Sizzle的主函数声明为例,来说明引擎的相关概念. function Sizzle(selector, context, results, seed) { //... ...

  9. JS封装动画框架,网易轮播图,旋转轮播图

    JS封装动画框架,网易轮播图,旋转轮播图 1. JS封装运动框架 // 多个属性运动框架 添加回调函数 function animate(obj,json,fn) { clearInterval(ob ...

随机推荐

  1. 剑指offer——已知二叉树的先序和中序排列,重构二叉树

    这是剑指offer中关于二叉树重构的一道题.题目原型为: 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2, ...

  2. 如何获取浏览器的DNS解析时间

    上一篇博客提到09年初WED团队开发的浏览器环境检测工具时,忘记说这个是aoao同学的创意了.不过没关系,据说他又在秘密规划新版本了,再据说新版要增加的DNS解析时间计算已经开发完成,点上面那个链接就 ...

  3. 第五章 Spring3.0 、Hibernate3.3与Struts2的整合 基于Annotation

    Annotation的方式是通过注解的方式把Struts2中的Action.Dao层的实现类.Service层的实现类交由Spring管理,不需要在配置文件中进行配置.但为了方便,事务的管理依然使用的 ...

  4. 圣何塞与 Microsoft 宣布该市为超过 5,000 名市府公务员选择 Office 365、Windows Azure 和 StorSimple

    过去几个月来我们展示了极大的客户吸引力,今天我们非常高兴地宣布,我们又赢得了一位新客户,且他们利用 Microsoft 革新 IT 的方式非常有趣. 今天,我们非常高兴地告诉大家,圣何塞市选择了 Mi ...

  5. iOS开发之主题皮肤

    iOS开发之主题皮肤 分类: [iOS]  最近在开发一款[公交应用],里面有个模块涉及到主题设置,这篇文章主要谈一下个人的做法. 大概的步骤如下: (1):整个应用依赖于一个主题管理器,主题管理器根 ...

  6. 在线词典php

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  7. ruby简单的基础 5

    方法和代码块 在Ruby中.{}或do...end之间的代码是一个代码块.代码块只能出如今一个方法的后边,它紧接在方法最后一个參数的同一行上,一般由yieldkeyword调用代码块中的代码. 方法是 ...

  8. asp.net弹出多个模态窗口

    asp.net中无限制弹出模态窗口 特点: 1.       可以在模态窗口上再弹出模态窗口,不限制次数 2.       弹出窗口的支持拖放,及调整大小 3.       弹出窗口关闭后可以动态控制 ...

  9. VS2015使用scanf报错解决方案

    版权声明:本文为博主原创文章,未经博主允许不得转载. 方法一:在程序最前面加#define _CRT_SECURE_NO_DEPRECATE: 方法二:在程序最前面加#define _CRT_SECU ...

  10. Javascript知识三

    O(∩_∩)O...今天继续学习了Javascript的知识,下面就总结一下. 数组: 判断是否为数组(instanceof Array) 在JavaScript中,数组不一定是同一类型 var ar ...