1. 程式人生 > >珠峰 JS 筆記3.2(DOM)

珠峰 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);
}

封裝選項卡函式
選項卡結構相同,但個數可能不同,當前展示項也不同