繼續5,6章小結(一)的內容,作者認為我們會用css中的選擇符來定位HTML DOM中的元素,給其添加樣式,那麼為什麼不利用css選擇符來定位得到我們想要的DOM節點呢,由於這樣的想法產生了jquery中靈活強大的選取器(selector)協助定位尋找元素,作者也簡要說明了下xpath。
如何獲得一個元素的常值內容,如:<p><strong>hello</strong>how are you doing?</p>
假定<strong>對應strongElem那麼 strongElem.innerText //非Mozilla核心的瀏覽器
strongElem.firstChild.nodeValue //適合所有平台
文中給出了一個通用的取出元素常值內容的函數
function text(e) {
var t = "";
//如果單個元素傳入,擷取它的子節點
//否則假設e是個節點數組
e = e.childNodes || e;
//遍曆所有的子節點
for(var j = 0; j < e.length; j++) {
//如果不是一個元素,追加到t
//否則遞迴遍曆它的所有子節點
t += e[j].nodeType != 1 ? e[j].nodeValue : text(e[j].childNodes);
}
//返回匹配的文本
return t;
}
擷取一個元素內的HTML,我們很快會想到innerHTML,但它只對HTML DOM有效對XML DOM就不行了。
關於元素的屬性,有個判定一個元素是否具有某個指定屬性的方法
function hasAttribute(elem, name) {
return elem.getAttribute(name) != null;
}
一對HTML,XML DOM的通用方法:getAttribute和setAttribute 例:id("everywhere").getAttribute("id") ;
tag("input")[0].setAttribute("value", "your name");
除了這對標準的方法,還有一些快速存取元素屬性的方式,如:tag("div")[0].id = "main"; tag("input")[0].value;
但是有一些屬性如class --> className, float-->cssFloat, text-->cssText,因為像class,float,text這些詞本來就是javascript中的保留字。
文中有個attr方法,通過參數個數決定它的作用是設定屬性值,還是擷取屬性值:
function attr(elem, name, value) {
//確保提供了一個有效name
if(!name || name.constructor != String) return "";
//理解不合常規的命名
name = {'for':'htmlFor', 'class':'className'}[name] || name;
//如果使用者傳入value
if(typeof value != 'undefined') {
//先用快速存取法
elem[name] = value;
//如果可以,用標準的setAttribute
if(elem.setAttribute) elem.setAttribute(name, value);
}
//返回屬性值
return elem[name] || elem.getAttribute(name) || '';
}
這個方法既能讀又能取,參數中如果不帶value那麼返回已有的屬性值,如果帶了value,那麼給對應的屬性設定值,這和jquery中的attr基本是一樣的,只不過我們用jquery的時候把DOM元素封裝成了jquery對象。
修改DOM包括建立,插入,刪除等,有了這些我們就能打造動態頁面效果,xhtml是xml一個子集,在建立元素時帶個namespace
function create(elem) {
return document.createElementNS ?
document.createElementNS('http://www.w3.org/1999/xhtml', elem) :
document.createElement(elem);
}
對於插入DOM,有兩個標準方法:parentBeforeNode.insertBefore(nodeToInsert, beforeNode)
parentElem.append(nodeToInsert)
相信大家對這兩個方法並不陌生,書中基於這兩個方法做了函數封裝
function before(parent, before, elem) {
//檢查是否提供父節點,如果像這樣調用:before(elem1, elem2)將elem2插到elem1之前
if(elem == null) {
elem = before;
before = parent;
parent = before.parentNode;
}
parent.insertBefore(checkElem(elem), before);
}
function append(parent, elem) {
parent.appendChild(checkElem(elem));
}
function checkElem(elem) {
//如果傳入的是個字串,那麼轉換成TextNode
return elem && elem.constructor == String ?
document.createTextNode(elem) : elem;
}
向元素中注入HTML,tag("ul")[0].innerHTML = "<li>Cats</li><li>Dogs</li><li>Mice</li>";
比起上面的方法來說,確實方便,但用innerHTML有以下缺點:
1.就像之前提到的,它不支援純粹的XML
2.innerHTML的賦值是把元素內的內容全部覆蓋掉,很不靈活
文章中作者給出了一個很不錯的解決方案:
function checkElem(a) {
var r = [];
//如果a不是數組,把a初始化為數組
if(a.constructor != Array) a = [a];
for(var i = 0; i < a.length; i++) {
//如果是構造HTML字串
if(a[i].constructor == String) {
//建立一個臨時元素來持有HTML
var div = document.createElement("div");
//注入這個HTML,把它轉變成DOM結構
div.innerHTML = a[i];
//從這個臨時的div中取出DOM元素
for(var j = 0; j < div.childNodes.length; j++) {
r[r.length] = div.childNodes[j];
}
} else if (a[i].length) {
//如果是它是個數組,假設是個DOM節點的數組
for(var j = 0; j < a[i].length; j++)
r[r.length] = a[i][j];
} else { //否則就假設它是個DOM節點
r[r.length] = a[i];
}
return r; //參數a解析後的dom節點數組
}
}
再把原來的before,append函數擴充下:
function before(parent, before, elem) {
if(elem == null) {
elem = before;
before = parent;
parent = before.parentNode;
}
//得到新的元素數組
var elems = checkElem(elem);
//倒序遍曆數組elems
for(var i = elems.length - 1; i >= 0; i--)
parent.insertBefore(elems[i], before);
}
function append(parent, elem) {
var elems = checkElem(elem);
for(var i = 0; i < elems.length; i++)
parent.appendChild(elems[i]);
}
然後我們就可以這樣調用了append(first(tag('ul')[0]), '<li>Mouse trap.</li>');而之前第二個參數只能是個單獨的節點(如<p>,<li>或者textNode);如此一來大大增強了可用性。
小結的第二部分就到這吧。。測試代碼下載