珠峰 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.
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);
}
封裝選項卡函式
選項卡結構相同,但個數可能不同,當前展示項也不同