珠峰 JS 笔记3.2(DOM)

> 获取页面中元素的方法

document.getElementById()
context.getElementsByTagName()
context.getElementsByClassName()  // 在 IE6-8 下不兼容
document.getElementsByName() // 在 IE 中只对表单元素的 name 起作用
document.body
document.documentElement
// 在 IE6-8 下不兼容,通过这个方法获取的节点集合不存在  DOM 映射
context.querySelector / context.querySelectorAll 

描述节点和节点之间关系的属性(在标准浏览器中会把空格和换行当做文本节点处理)
childNodes 
children   在 IE6-8 下获取的结果和标准浏览器获取的结果不一致
parentNode
previousSibling / previousElementSibling
nextSibling / nextElementSibling 
lastChild / lastElementChild 
firstChild / firstElementChild 

自己写一个 类似 children 的兼容的方法
\ 判断是否需要兼容处理
\ 自己处理的返回的是一个数组,直接用 children 返回的是一个类数组
\ 元素节点 nodeType ===1
\ for( var i=0, len = nodeList.length; i<len; i++ )
\ if( /MSIE (6|7|8)/i.test(navigator.userAgent) )
\ ary = Array.prototype.slice.call(curEle.children)
\ 增加要求: 获取指定元素的子元素 传指定元素参数

var utils = (function(){    // 工具集
	var flag = 'getComputedStyle' in window; // 判断
	return {
		xxx: function(){...}
	}
})();
// 惰性思想:
// 有多个属性方法在IE 6-8 下不兼容,可以定义一个变量 flag 判断,
// 在后面的判断中,只要判断 flag 就可以了
function getChild(obj , tagName ){
	var res = [];  //  数组 
	if( /MSID (6|7|8)/.test(window.navigator.userAgent)){
		//先获取所有节点,再根据 nodeType = 1 选出元素节点
		var temp = obj.childNodes;	
		for( var i=0; len=temp.length, i<len; i++){
			if( 1 === temp[i].nodeType){   // 类型判断
				res[res.length] = temp[i];
			}
		}
		temp = null; // 置空
	} else {
		// res = obj.children; // 这里得到不是数组
		res = Array.prototype.slice.call(obj.children);
	}	
	// 二次筛选 
	if( typeof tagName === 'string'){  // 传入的参数类型
		for( var k=0;  k<res.length; k++ ){  // for 循环写法的区别
			if(tagName.toLowerCase() !== res[k].nodeName.toLowerCase()){  // 小写
				res.splice(k,1); // 删除不符合要求的项
				k--;
			}
		}
	}
	return res;
}
// 再考虑多传一个元素,查找指定子元素
console.log(getChild(document.body,'p').length);

工具集
在自执行函数的私有作用域中定义函数 getChildNodes
在 return 中添加 getChildNodes: getChildNodes, …

> 获取兄弟元素节点

获取上一个元素节点 prev

// 获取元素上一个兄弟节点
// 兼容,标准浏览器直接返回,ie6-8 判断类型再返回
function prev(ele){
	if(flag){
		return ele.previousElementSibling;
	} 
	var pre = ele.previousSibling;
	while(pre && pre.nodeType !== 1){
		pre = pre.previousSibling;
	}
	return pre;
}

获取前面所有的兄弟节点

// 获取前面所有兄弟节点
function prevAll(ele){
	var ary = [];  
	var pre = this.prev(ele);  // this 
	while(ele){
		ary.unshift(pre);  // 从第一个插入
		pre = this.prev(pre); 
	}
	return ary;
}
// 获取元素前一个元素和后一个元素
function sibling(ele){
	var pre = this.prev(ele);
	var nex = this.next(ele);
	var ary = [];
	pre ? ary.push(pre) : null;
	nex ? ary.push(nex) : null;
	return ary;
}
// 获取元素所有元素节点
function siblings(ele){
	return this.prevAll(ele).concat(this.nextAll(ele));
}
// 获取元素下标 
function index(ele){
	return this.prevAll(ele).length;
}
// 获取元素的第一个子元素
function firstChild(ele){
	var res = this.getChildNodes(ele);
	return res.length > 0 ? res[0] : null; 
}
// 获取元素最后一个子元素
function lastChild(ele){
	var res = this.getChildNodes(ele);
	return res.length >0 ? res[res.length] : null;
}

插入元素

// 向容器元素的最前面插入元素方法
function prepend(newEle, container){
	var fir = this.firstChild(container);
	if(fir){
		container.insertBefore(newEle, fir); // 在第一个元素的前面插入
		return; 
	}
	container.appendChild(newEle);
}
// 向指定元素的后面插入元素
function insertAfter(newEle,oldEle){
	var nex = this.next(oldEle); // 元素的后一个节点
	if(nex){  // 如果存在后一个节点
		oldEle.parentNode.insertBefore(newEle,nex);
		return;
	}
	oldEle.parentNode.appendChild(newEle);
}

操作元素的样式类

// 验证当前元素是否包含 className 这个样式类
function hasClass(curEle, cName){
	var reg = new RegExp('(^| +)'+cName +'( +|&)');
	return reg.test(curEle.className);
}
// 添加 样式类
function addClass(curEle, cName){
	var classAry = cName.split(/ +/g);  // 用正则  可能有多个空格
	for(var i=0; i<classAry.length; i++){
		if(!hasClass(curEle,classAry[i])){ // 不存在
			curEle.className += classAry[i];
		}
	}
}

删除某个样式类
如上代码,在 for 循环中,判断存在要删除的类型,再操作

var reg = new RegExp("(^| +)"+ classAry[i] + "( +|$)","g"); // 
curEle.className = curEle.className.replace(reg, " "); // 用空格替换

删除首尾空格

"  c  a b ".replace(/(^ +| +$)/g, '')

getElementsByClassName 的兼容处理

// context: 获取元素的上下文,如果不传这个参数的话,默认为 document
function _getElementsByClassName(cName, context) {
	context = context || document;
	if(flag){  // 标准浏览器  这里返回的是一个类数组集合
		return context.getElementsByClassName(cName);
	}
	var res = [];	
	var classAry = cName.replace(/(^ +| +$)/g, "").split(/ +/g); // 去除首尾空格,拆成数组
	// 获取指定上下文所有元素
	var allEleAry = context.getElementsByTagName("*"); // 通配符 
	for(var i = 0; i < allEleAry.length; i++) {
		for(var j = 0; j < classAry.length; j++) {
			var hc = true;
			if(!hasClass(allEleAry[i], classAry[j])) { // 要同时拥有传进来的所有的样式类
				hc = false;
				break;
			}
			if(hc) {
				res.push(allEleAry[i]);
			}
		}
	}
	return res;
}

设置元素样式
在 JS 中设置元素样式,只能通过 curEle.style[attr] = value 来设置行内样式
自定义一个设置元素的方法,考虑 单位问题、兼容性问题、float

function setCss(curEle, attr, value){
	// 考虑要加单位的情况    注意后面的首字母大写
	var reg = /^(width|height|top|bottom|left|right|((margin|padding)(Top|Bottom|Right|Left)?))$/; // 正则
	if(reg.test(attr)){  // 从属性判断是否要加单位
		if(!isNaN(value)){
			console.log('单位');
			value += 'px';
		}
	}
	// 还可能 的兼容的问题  opacity
	if('opacity' === attr){
		curEle['style'][attr] = value;
		curEle['style']['filter'] = 'alpha(opacity = '+ value*100 +')';
		console.log('aa');
		return;
	}
	// 在 JS 中设置 float 也要处理兼容 
	if('float'=== attr){
		curEle['style']["cssFloat"] = value;
		curEle['style']["styleFloat"] = value;
		return;
	}
	curEle['style'][attr] = value;
}
setCss(oBox,"borderTop","2px solid #333"); // 使用

批量设置元素样式

function setGroupCss(curEle,options){
	// 先判断第二个参数存在,还有值的类型
	options= options|| 0;
	if(Object.prototype.toString.call(options) !== '[object Object]'){
		// 用 options.toString() 也可以
		return;  
	}
	for( var key in options){
		if( options.hasOwnProperty(key)){  // 
			setCss(curEle,key,options[key]);
		}
	}
}

获取样式设置样式方法合并 以参数的个数及类型来判断要进行的操作

> 选项卡

css:
overflow: hidden; 清除子元素浮动对父级的影响
clear: both; 前一元素子元素浮动,给后一元素加 清除前面元素浮动对后面元素的影响
-webkit-user-select: none; 禁止用户选定

选项卡和内容页都是先设置 display: none; , 添加类名后才: display: block;
结构
#tab > ul + div*3 div 是内容区域
ul > li *3 li 是选项卡

var tab = document.getElementById('tab');
var tabLiss = tab.getElementsByTagName('li'); // 所有的选项卡
var tabDivs = tab.getElementsByTagName("div"); // 所有的内容

for( var i=0; i<tabLiss.length; i++){
	tabLiss[i].index = i;  // 自定义变量
	tabLiss[i].onclick = function(){
		changeCt(this.index);
	}
}
function changeCt(n){
	for(var i=0; i<tabDivs.length; i++){
		tabDivs[i].className = 'none';  // 修改类名
		tabLiss[i].className = 'none';
	}
	tabDivs[n].className = 'selet';
	tabLiss[n].className = 'selet';
}

也可以用闭包的方法解决

for( var i=0; i<tabLiss.length; i++){
	+function(i){  // 形成一个私有的作用域 
		tabLiss[i].onclick = function(){
			changeCt(i);
		}
	}(i);  
}
for( var i=0; i<tabLiss.length; i++){
	tabLiss[i].onclick = (function(i){
		return function(){  // 这样也可以
			changeCt(i);
		}
	})(i);
}

封装选项卡函数
选项卡结构相同,但个数可能不同,当前展示项也不同

猜你喜欢

转载自blog.csdn.net/asjean/article/details/84542989