JS 封装CSS选择器式的获取元素方法
之前的章节使用都是单一式获取方法,一次只能获得单个或者对应的元素数组,唯一加了获取条件的就是通过class获取元素,我们加了一个用于筛选的idName,当idName存在,class要从这个idName元素下获取,但是这样也不能方便的使用,万一我们要在某个class元素下搜索某个tagName或者class,之前的方法完全不够用了。为此我们衍生出新的获取元素的方法。
我们的希望获取元素可以这样写:
$('#er span i').css('color','red')
获取id为er的元素下的span元素中的i元素,让他的颜色改为红色。
html代码如下:
<p id="er">
<span id="ps">span</span>
<span class="td"><i>sad</i>span</span>
<span>span</span>
</p>
首先我们要对$('#er span i')传入的参数进行调整,传入的是string类型,我们可以通过split()将他转换为数组,但是我们也可能会只传入一个元素,他没有空格这些所以还要做个判断。
//调用Base
var $ = function(args) {
return new Base(args);
}
//基础库
function Base(args) {
this.arr = [];
if(args.indexOf(' ') != -1){
}else {
}
}
从简单的开始我们先判断传入的参数为#er
//调用Base
var $ = function(args) {
return new Base(args);
}
//基础库
function Base(args) {
this.arr = [];
if(args.indexOf(' ') != -1){
}else {
//如果传入的值是文本
if(typeof args == 'string') {
if(args.charAt(0) == '#') {
this.arr.push(this.getId(args.substring(1)));
}
}else if(typeof args == 'object') {
//因为之前事件绑定时还传过this对象,这里做个兼容
if(args != undefined) {
this.arr[0] = args;
}
}
}
}
//获取id元素
Base.prototype.getId = function(id) {
return document.getElementById(id);
}
通过charAt(0)获取到第一位的值,判断是否为‘#’,如果是的话运行获取id的方法,因为我们现在使用的是$(),在这个方法里面就直接获取到了元素,所以Base.prototype.getId方法也不需要return this了,然后因为id是单个存在的,所以直接返回获取到的对象就行,然后将返回的对象push到数组arr中。
实际上我们传入的参数有三种可能,一种是id,一种是class,一种是tagName,那么每次都 if(args.charAt(0) == 'xxx')来判断有点麻烦,这个if判断要重复写很多次,索性使用switch方法判断。
//基础库
function Base(args) {
this.arr = [];
if(args.indexOf(' ') != -1){
}else {
//如果传入的值是文本
if(typeof args == 'string') {
switch(args.charAt(0)) {
case '#' :
this.arr.push(this.getId(args.substring(1)));
break;
case '.' :
break;
default :
}
}else if(typeof args == 'object') {
//因为之前事件绑定时还传过this对象,这里做个兼容
if(args != undefined) {
this.arr[0] = args;
}
}
}
}
现在判断传入的是class:
//基础库
function Base(args) {
this.arr = [];
if(args.indexOf(' ') != -1){
}else {
//如果传入的值是文本
if(typeof args == 'string') {
switch(args.charAt(0)) {
case '#' :
this.arr.push(this.getId(args.substring(1)));
break;
case '.' :
this.arr = this.getclass(args.substring(1));
break;
default :
}
}else if(typeof args == 'object') {
//因为之前事件绑定时还传过this对象,这里做个兼容
if(args != undefined) {
this.arr[0] = args;
}
}
}
}
//获取class元素和id筛选
Base.prototype.getclass = function(className,parentNode) {
var node = null;
var temps = [];
if(parentNode != undefined) {
node = parentNode;
}else {
node = document;
}
var elements = node.getElementsByTagName('*');
for(var i = 0;i<elements.length;i++) {
if(elements[i].className.match(className)) {
temps.push(elements[i]);
}
}
return temps;
}
因为getclass方法return的是数组,所以直接this.arr = 返回的数组就行。
判断传入的是tagName
//基础库
function Base(args) {
this.arr = [];
if(args.indexOf(' ') != -1){
}else {
//如果传入的值是文本
if(typeof args == 'string') {
switch(args.charAt(0)) {
case '#' :
this.arr.push(this.getId(args.substring(1)));
break;
case '.' :
this.arr = this.getclass(args.substring(1));
break;
default :
this.arr = this.getTagName(args);
}
}else if(typeof args == 'object') {
//因为之前事件绑定时还传过this对象,这里做个兼容
if(args != undefined) {
this.arr[0] = args;
}
}
}
}
//通过元素名获取元素
Base.prototype.getTagName = function(tag,parentNode) {
var node = null;
var temps = [];
if(parentNode != undefined) {
node = parentNode;
}else {
node = document;
}
var tags = node.getElementsByTagName(tag);
for(var i = 0;i<tags.length;i++){
temps.push(tags[i]);
}
return temps;
}
getTagName 也是返回的数组,和上面一样this.arr = 返回的数组即可。
下面就是重点了,当传入的参数是复合形式#er span
//基础库
function Base(args) {
this.arr = [];
if(args.indexOf(' ') != -1){
var childNodes = args.split(' ');
var temNodes = [];
var node = [];
for(var i = 0;i < childNodes.length;i++) {
if(node.length == 0) node.push(document);
switch(childNodes[i].charAt(0)) {
case '#' :
temNodes = [];
temNodes.push(this.getId(childNodes[i].substring(1)));
node = temNodes;
break;
case '.' :
temNodes = [];
for(var j = 0;j<node.length;j++) {
var temps = this.getclass(childNodes[i].substring(1),node[j]);
for(var k = 0;k<temps.length;k++){
temNodes.push(temps[k])
}
}
node = temNodes;
break;
default :
temNodes = [];
alert(node[0].innerHTML)
for(var j = 0;j<node.length;j++) {
var temps = this.getTagName(childNodes[i],node[j]);
for(var k = 0;k<temps.length;k++){
temNodes.push(temps[k])
}
}
node = temNodes;
}
}
this.arr = temNodes;
}else {
//如果传入的值是文本
if(typeof args == 'string') {
switch(args.charAt(0)) {
case '#' :
this.arr.push(this.getId(args.substring(1)));
break;
case '.' :
this.arr = this.getclass(args.substring(1));
break;
default :
this.arr = this.getTagName(args);
}
}else if(typeof args == 'object') {
//因为之前事件绑定时还传过this对象,这里做个兼容
if(args != undefined) {
this.arr[0] = args;
}
}
}
}
首先创建一个childNodes 变量用来保存args.split(' ')生成的数组,然后再for语句循环这个childNodes里面的值,每个值循环一次,判断是ID,还是class,还是tagName。
如果是ID,那么就运行this.getId(childNodes[i].substring(1)),将搜索的值传入,然后由于是复合式的,我们还要考虑他第二次会有父元素,但是id的方法getElementById只能作用于document,而且id只有一个,所以也没必要传第二个值,但是thia.arr不能通过push的方法传入了,不然你第一次是push,第二次也是push,那你不是都给获取了,根本没有获取范围的效果,所以这里要额外创建一个数组temNodes来临时保存返回的值。
temNodes也是push方法,这样就导致没啥效果啊,和this.arr.push一样,所以在temNodes.push之前要对这个数组重置。temNodes = [];
当for循环完args后,temNodes得到的就是最终的结果,所以我们要将这个结果返回给this.arr,this.arr = temNodes;
当for循环args第二遍时,就会产生父元素用于筛选,id的话可以不用考虑这个父元素,但是如果传入的参数为 #er span,那么span是在#er里面的,我们不可能用temNodes[0]的方式来表示父元素,因为temNodes在返回值之前都会被重置掉,这里我们又要创建一个新的数组node用来保存父元素,所以id在返回完值后也要将这个返回的值传入push中,索性直接就是node = temNodes;
这样每次返回完值后,都要将值传给node,作为下次循环的时候作为父元素存在。
id部分好了,下面为class的时候
也是一样,先重置临时数组temNodes,因为有node的存在,你不知道node里面有多少个值,所以做个for循环,这里的for不能用i了,要用其他的命名,一面和for循环childNodes的i冲突,循环node数组,然后运行this.getclass(childNodes[i].substring(1),node[j]),返回的是一个数组,但是不能直接=temNodes,不然for循环node的时候会无限覆盖,下一个覆盖上一个,这里用一个temps元素保存返回的数组,然后for循环这个数组,依次push到temNodes中去,这样当node数组循环完后,也就得到了所有node元素的下元素了。
得到结果后将结果再传给node,下次循环的时候作为父元素存在。
使用了node就会产生一个问题,如果你是第一次使用的话,你的class又使用了for循环node数组,但是第一次并没有产生node啊,所以在第一次for循环childNodes的时候做个判断,如果没有node表示是第一次,第一次获取都是在document上的,于是if(node.length == 0) node.push(document);
下面就是tagName了
先重置temNodes,然后for循环node数组,和class一样,只是调用的方法为this.getTagName(childNodes[i],node[j]);得到值后再将值传给node。
当for循环childNodes完毕后,表示已经处理完你传入的最后一个参数了,那么将最终的结果返回给arr数组: this.arr = temNodes;
关于获取元素时的第二个参数
在使用getTagName和getclass的时候都要考虑到父元素的存在,所以要传入第二个参数,但是第一次的时候并不会传入第二个参数,所以做个if判断,if(parentNode != undefined)表示parentNode 有值,将node=parentNode ,如果没有就node = document;然后获取的时候从node开始:node.getElementsByTagName('*')....
以上就是封装使用css选择器的方式获取元素了,实际上还有更多的方法,比如>,last-child等等选择器,这些就暂时不弄,等我
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据