国产激情自拍_国产9色视频_丁香花在线电影小说观看 _久久久久国产精品嫩草影院

首頁(yè) > 開(kāi)發(fā) > XML > 正文

輕松使用DOM 的技巧和訣竅

2024-09-05 20:53:56
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友
,歡迎訪問(wèn)網(wǎng)頁(yè)設(shè)計(jì)愛(ài)好者web開(kāi)發(fā)。

  dethe elza (delza@livingcode.org), 高級(jí)技術(shù)架構(gòu)師, blast radius
 
  文檔對(duì)象模型(document object model,dom)是用于操縱 xml 和 html 數(shù)據(jù)的最常用工具之一,然而它的潛力卻很少被充分挖掘出來(lái)。通過(guò)利用 dom 的優(yōu)勢(shì),并使它更加易用,您將獲得一款應(yīng)用于 xml 應(yīng)用程序(包括動(dòng)態(tài) web 應(yīng)用程序)的強(qiáng)大工具。

  本期文章介紹了一位客串的專欄作家,同時(shí)也是我的朋友和同事 dethe elza。dethe 在利用 xml 進(jìn)行 web 應(yīng)用程序開(kāi)發(fā)方面經(jīng)驗(yàn)豐富,在此,我要感謝他對(duì)我在介紹使用 dom 和 ecmascript 進(jìn)行 xml 編程這一方面的幫助。

 —— david mertz

  dom 是處理 xml 和 html 的標(biāo)準(zhǔn) api 之一。由于它占用內(nèi)存大、速度慢,并且冗長(zhǎng),所以經(jīng)常受到人們的指責(zé)。盡管如此,對(duì)于很多應(yīng)用程序來(lái)說(shuō),它仍然是最佳選擇,而且比 xml 的另一個(gè)主要 api —— sax 無(wú)疑要簡(jiǎn)單得多。dom 正逐漸出現(xiàn)在一些工具中,比如 web 瀏覽器、svg 瀏覽器、openoffice,等等。

  dom 很好,因?yàn)樗且环N標(biāo)準(zhǔn),并且被廣泛地實(shí)現(xiàn),同時(shí)也內(nèi)置到其他標(biāo)準(zhǔn)中。作為標(biāo)準(zhǔn),它對(duì)數(shù)據(jù)的處理與編程語(yǔ)言無(wú)關(guān)(這可能是優(yōu)點(diǎn),也可能是缺點(diǎn),但至少使我們處理數(shù)據(jù)的方式變得一致)。dom 現(xiàn)在不僅內(nèi)置于 web 瀏覽器,而且也成為許多基于 xml 的規(guī)范的一部分。既然它已經(jīng)成為您的工具的一部分,并且或許您偶爾還會(huì)使用它,我想現(xiàn)在應(yīng)該充分利用它給我們帶來(lái)的功能了。

  在使用 dom 一段時(shí)間后,您會(huì)看到形成了一些模式 —— 您想要反復(fù)做的事情。快捷方式可以幫助您處理冗長(zhǎng)的 dom,并創(chuàng)建自解釋的、優(yōu)雅的代碼。這里收集了一些我經(jīng)常使用的技巧和訣竅,還有一些 javascript 示例。

insertafter 和 prependchild

    第一個(gè)訣竅就是“沒(méi)有訣竅”。dom 有兩種方法將孩子節(jié)點(diǎn)添加到容器節(jié)點(diǎn)(常常是一個(gè) element,也可能是一個(gè) document 或 document fragment):appendchild(node) 和 insertbefore(node, referencenode)。看起來(lái)似乎缺少了什么。假如我想在一個(gè)參考節(jié)點(diǎn)后面插入或者由前新增(prepend)一個(gè)子節(jié)點(diǎn)(使新節(jié)點(diǎn)位于列表中的第一位),我該怎么做呢?很多年以來(lái),我的解決方法是編寫下列函數(shù):

  清單 1. 插入和由前新增的錯(cuò)誤方法

function insertafter(parent, node, referencenode) {
    if(referencenode.nextsibling) {
        parent.insertbefore(node, referencenode.nextsibling);
    } else {
        parent.appendchild(node);
    }
}
function prependchild(parent, node) {
    if (parent.firstchild) {
        parent.insertbefore(node, parent.firstchild);
    } else {
        parent.appendchild(node);
    }
}
 
  實(shí)際上,像清單 1 一樣,insertbefore() 函數(shù)已經(jīng)被定義為,在參考節(jié)點(diǎn)為空時(shí)返回到 appendchild()。因此,您可以不使用上面的方法,而使用 清單 2 中的方法,或者跳過(guò)它們僅使用內(nèi)置函數(shù):

  清單 2. 插入和由前新增的正確方法

function insertafter(parent, node, referencenode) {
    parent.insertbefore(node, referencenode.nextsibling);
}
function prependchild(parent, node) {
    parent.insertbefore(node, parent.firstchild);
}
 
  如果您剛剛接觸 dom 編程,有必要指出的是,雖然您可以使多個(gè)指針指向一個(gè)節(jié)點(diǎn),但該節(jié)點(diǎn)只能存在于 dom 樹(shù)中的一個(gè)位置。因此,如果您想將它插入到樹(shù)中,沒(méi)必要先將它從樹(shù)中移除,因?yàn)樗鼤?huì)自動(dòng)被移除。當(dāng)重新將節(jié)點(diǎn)排序時(shí),這種機(jī)制很方便,僅需將節(jié)點(diǎn)插入到新位置即可。

  根據(jù)這種機(jī)制,若想交換兩個(gè)相鄰節(jié)點(diǎn)(稱為 node1 和 node2)的位置,可以使用下列方案之一:

node1.parentnode.insertbefore(node2, node1);

node1.parentnode.insertbefore(node1.nextsibling, node1);

  還可以使用 dom 做什么?

  web 頁(yè)面中大量應(yīng)用了 dom。若訪問(wèn) bookmarklets 站點(diǎn)(參閱 參考資料),您會(huì)發(fā)現(xiàn)很多有創(chuàng)意的簡(jiǎn)短腳本,它們可以重新編排頁(yè)面,提取鏈接,隱藏圖片或 flash 廣告,等等。

  但是,因?yàn)?internet explorer 沒(méi)有定義 node 接口常量(可以用于識(shí)別節(jié)點(diǎn)類型),所以您必須確保在遺漏接口常量時(shí),首先為 web 在 dom 腳本中定義接口常量。

  清單 3. 確保節(jié)點(diǎn)被定義

if (!window['node']) {
    window.node = new object();
    node.element_node = 1;
    node.attribute_node = 2;
    node.text_node = 3;
    node.cdata_section_node = 4;
    node.entity_reference_node = 5;
    node.entity_node = 6;
    node.processing_instruction_node = 7;
    node.comment_node = 8;
    node.document_node = 9;
    node.document_type_node = 10;
    node.document_fragment_node = 11;
    node.notation_node = 12;
}
 
  清單 4 展示如何提取包含在節(jié)點(diǎn)中的所有文本節(jié)點(diǎn):

  清單 4. 內(nèi)部文本

function innertext(node) {
    // is this a text or cdata node?
    if (node.nodetype == 3 || node.nodetype == 4) {
        return node.data;
    }
    var i;
    var returnvalue = [];
    for (i = 0; i < node.childnodes.length; i++) {
        returnvalue.push(innertext(node.childnodes[i]));
    }
    return returnvalue.join('');
}
 

  快捷方式

  人們常常抱怨 dom 太過(guò)冗長(zhǎng),并且簡(jiǎn)單的功能也需要編寫大量代碼。例如,如果您想創(chuàng)建一個(gè)包含文本并響應(yīng)點(diǎn)擊按鈕的 <div> 元素,代碼可能類似于:

  清單 5. 創(chuàng)建 <div> 的“漫長(zhǎng)之路”

function handle_button() {
    var parent = document.getelementbyid('mycontainer');
    var div = document.createelement('div');
    div.classname = 'mydivcssclass';
    div.id = 'mydivid';
    div.style.position = 'absolute';
    div.style.left = '300px';
    div.style.top = '200px';
    var text = "this is the first text of the rest of this code";
    var textnode = document.createtextnode(text);
    div.appendchild(textnode);
    parent.appendchild(div);
}

  若頻繁按照這種方式創(chuàng)建節(jié)點(diǎn),鍵入所有這些代碼會(huì)使您很快疲憊不堪。必須有更好的解決方案 —— 確實(shí)有這樣的解決方案!下面這個(gè)實(shí)用工具可以幫助您創(chuàng)建元素、設(shè)置元素屬性和風(fēng)格,并添加文本子節(jié)點(diǎn)。除了 name 參數(shù),其他參數(shù)都是可選的。

  清單 6. 函數(shù) elem() 快捷方式

function elem(name, attrs, style, text) {
    var e = document.createelement(name);
    if (attrs) {
        for (key in attrs) {
            if (key == 'class') {
                e.classname = attrs[key];
            } else if (key == 'id') {
                e.id = attrs[key];
            } else {
                e.setattribute(key, attrs[key]);
            }
        }
    }
    if (style) {
        for (key in style) {
            e.style[key] = style[key];
        }
    }
    if (text) {
        e.appendchild(document.createtextnode(text));
    }
    return e;
}
 
  使用該快捷方式,您能夠以更加簡(jiǎn)潔的方法創(chuàng)建 清單 5 中的 <div> 元素。注意,attrs 和 style 參數(shù)是使用 javascript 文本對(duì)象而給出的。

  清單 7. 創(chuàng)建 <div> 的簡(jiǎn)便方法

function handle_button() {
    var parent = document.getelementbyid('mycontainer');
    parent.appendchild(elem('div',
      {class: 'mydivcssclass', id: 'mydivid'}
      {position: 'absolute', left: '300px', top: '200px'},
      'this is the first text of the rest of this code'));
}

  在您想要快速創(chuàng)建大量復(fù)雜的 dhtml 對(duì)象時(shí),這種實(shí)用工具可以節(jié)省您大量的時(shí)間。模式在這里就是指,如果您有一種需要頻繁創(chuàng)建的特定的 dom 結(jié)構(gòu),則使用實(shí)用工具來(lái)創(chuàng)建它們。這不但減少了您編寫的代碼量,而且也減少了重復(fù)的剪切、粘貼代碼(錯(cuò)誤的罪魁禍?zhǔn)祝⑶以陂喿x代碼時(shí)思路更加清晰。
   
  接下來(lái)是什么?

  dom 通常很難告訴您,按照文檔的順序,下一個(gè)節(jié)點(diǎn)是什么。下面有一些實(shí)用工具,可以幫助您在節(jié)點(diǎn)間前后移動(dòng):

  清單 8. nextnode 和 prevnode

// return next node in document order
function nextnode(node) {
    if (!node) return null;
    if (node.firstchild){
        return node.firstchild;
    } else {
        return nextwide(node);
    }
}
// helper function for nextnode()
function nextwide(node) {
    if (!node) return null;
    if (node.nextsibling) {
        return node.nextsibling;
    } else {
        return nextwide(node.parentnode);
    }
}
// return previous node in document order
function prevnode(node) {
    if (!node) return null;
    if (node.previoussibling) {
      return previousdeep(node.previoussibling);
    }
    return node.parentnode;
}
// helper function for prevnode()
function previousdeep(node) {
    if (!node) return null;
    while (node.childnodes.length) {
        node = node.lastchild;
    }
    return node;
}

  輕松使用 dom

  有時(shí)候,您可能想要遍歷 dom,在每個(gè)節(jié)點(diǎn)調(diào)用函數(shù)或從每個(gè)節(jié)點(diǎn)返回一個(gè)值。實(shí)際上,由于這些想法非常具有普遍性,所以 dom level 2 已經(jīng)包含了一個(gè)稱為 dom traversal and range 的擴(kuò)展(為迭代 dom 所有節(jié)點(diǎn)定義了對(duì)象和 api),它用來(lái)為 dom 中的所有節(jié)點(diǎn)應(yīng)用函數(shù)和在 dom 中選擇一個(gè)范圍。因?yàn)檫@些函數(shù)沒(méi)有在 internet explorer 中定義(至少目前是這樣),所以您可以使用 nextnode() 來(lái)做一些
類似的事情。

  在這里,我們的想法是創(chuàng)建一些簡(jiǎn)單、普通的工具,然后以不同的方式組裝它們來(lái)達(dá)到預(yù)期的效果。如果您很熟悉函數(shù)式編程,這看起來(lái)會(huì)很親切。beyond js 庫(kù)(參閱 參考資料)將此理念發(fā)揚(yáng)光大。

  清單 9. 函數(shù)式 dom 實(shí)用工具

// return an array of all nodes, starting at startnode and
// continuing through the rest of the dom tree
function listnodes(startnode) {
    var list = new array();
    var node = startnode;
    while(node) {
        list.push(node);
        node = nextnode(node);
    }
    return list;
}
// the same as listnodes(), but works backwards from startnode.
// note that this is not the same as running listnodes() and
// reversing the list.
function listnodesreversed(startnode) {
    var list = new array();
    var node = startnode;
    while(node) {
        list.push(node);
        node = prevnode(node);
    }
    return list;
}
// apply func to each node in nodelist, return new list of results
function map(list, func) {
    var result_list = new array();
    for (var i = 0; i < list.length; i++) {
        result_list.push(func(list[i]));
    }
    return result_list;
}
// apply test to each node, return a new list of nodes for which
// test(node) returns true
function filter(list, test) {
    var result_list = new array();
    for (var i = 0; i < list.length; i++) {
        if (test(list[i])) result_list.push(list[i]);
    }
    return result_list;
}
 

  清單 9 包含了 4 個(gè)基本工具。listnodes() 和 listnodesreversed() 函數(shù)可以擴(kuò)展到一個(gè)可選的長(zhǎng)度,這與 array 的 slice() 方法效果類似,我把這個(gè)作為留給您的練習(xí)。另一個(gè)需要注意的是,map() 和 filter() 函數(shù)是完全通用的,用于處理任何 列表(不只是節(jié)點(diǎn)列表)。現(xiàn)在,我向您展示它們的幾種組合方式。

  清單 10. 使用函數(shù)式實(shí)用工具

// a list of all the element names in document order
function iselement(node) {
    return node.nodetype == node.element_node;
}
function nodename(node) {
    return node.nodename;
}
var elementnames = map(filter(listnodes(document),iselement), nodename);
// all the text from the document (ignores cdata)
function istext(node) {
    return node.nodetype == node.text_node;
}
function nodevalue(node) {
    return node.nodevalue;
}
var alltext = map(filter(listnodes(document), istext), nodevalue);
 

  您可以使用這些實(shí)用工具來(lái)提取 id、修改樣式、找到某種節(jié)點(diǎn)并移除,等等。一旦 dom traversal and range api 被廣泛實(shí)現(xiàn),您無(wú)需首先構(gòu)建列表,就可以用它們修改 dom 樹(shù)。它們不但功能強(qiáng)大,并且工作方式也與我在上面所強(qiáng)調(diào)的方式類似。

  dom 的危險(xiǎn)地帶

  注意,核心 dom api 并不能使您將 xml 數(shù)據(jù)解析到 dom,或者將 dom 序列化為 xml。這些功能都定義在 dom level 3 的擴(kuò)展部分“l(fā)oad and save”,但它們還沒(méi)有被完全實(shí)現(xiàn),因此現(xiàn)在不要考慮這些。每個(gè)平臺(tái)(瀏覽器或其他專業(yè) dom 應(yīng)用程序)有自己在 dom 和 xml間轉(zhuǎn)換的方法,但跨平臺(tái)轉(zhuǎn)換不在本文討論范圍之內(nèi)。

  dom 并不是十分安全的工具 —— 特別是使用 dom api 創(chuàng)建不能作為 xml 序列化的樹(shù)時(shí)。絕對(duì)不要在同一個(gè)程序中混合使用 dom1 非名稱空間 api 和 dom2 名稱空間感知的 api(例如,createelement 和 createelementns)。如果您使用名稱空間,請(qǐng)盡量在根元素位置聲明所有名稱空間,并且不要覆蓋名稱空間前綴,否則情況會(huì)非常混亂。一般來(lái)說(shuō),只要按照慣例,就不會(huì)觸發(fā)使您陷入麻煩的臨界情況。

  如果您一直使用 internet explorer 的 innertext 和 innerhtml 進(jìn)行解析,那么您可以試試使用 elem() 函數(shù)。通過(guò)構(gòu)建類似的一些實(shí)用工具,您會(huì)得到更多便利,并且繼承了跨平臺(tái)代碼的優(yōu)越性。將這兩種方法混合使用是非常糟糕的。

  某些 unicode 字符并沒(méi)有包含在 xml 中。dom 的實(shí)現(xiàn)使您可以添加它們,但后果是無(wú)法序列化。這些字符包括大多數(shù)的控制字符和unicode 代理對(duì)(surrogate pair)中的單個(gè)字符。只有您試圖在文檔中包含二進(jìn)制數(shù)據(jù)時(shí)才會(huì)遇到這種情況,但這是另一種轉(zhuǎn)向(gotcha)情況。

  結(jié)束語(yǔ)

  我已經(jīng)介紹了 dom 能做的很多事情,但是 dom(和 javascript)可以做的事情遠(yuǎn)不止這些。仔細(xì)研究、揣摩這些例子,看看是如何使用它們來(lái)解決可能需要客戶端腳本、模板或?qū)S?api 的問(wèn)題。

  dom 有自己的局限性和缺點(diǎn),但同時(shí)也擁有眾多優(yōu)點(diǎn):它內(nèi)置于很多應(yīng)用程序中;無(wú)論使用 java 技術(shù)、python 或 javascript,它都以相同方式工作;它非常便于使用 sax;使用上述的模板,它使用起來(lái)既簡(jiǎn)潔又強(qiáng)大。越來(lái)越多的應(yīng)用程序開(kāi)始支持 dom,這包括基于 mozilla的應(yīng)用程序、openoffice 和 blast radius 的 xmetal。越來(lái)越多的規(guī)范需要 dom,并對(duì)它加以擴(kuò)展(例如,svg),因此 dom 時(shí)時(shí)刻刻就在您的身邊。使用這種被廣泛部署的工具,絕對(duì)是您的明智之舉。

  請(qǐng)作者聯(lián)系本站,及時(shí)附注您的姓名。聯(lián)系郵箱:edu#chinaz.com(把#改為@)。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
国产激情自拍_国产9色视频_丁香花在线电影小说观看 _久久久久国产精品嫩草影院
91这里只有精品| 国产一级又黄| 香蕉视频在线观看www| 奇米影视狠狠狠| 国产福利免费在线观看| 日本中文字幕高清视频| 二人午夜免费观看在线视频| 青青久在线视频免费观看| 亚洲精品视频区| 精精国产xxxx视频在线动漫| 国产午夜视频| 国产精品视频一区二区久久| 国产经典av| 久久99精品久久久久久野外| 黄色毛片在线看| 中文字幕在线观看日本| 在线国产91| 国产人成网在线播放va免费| 亚洲成人av在线影院| 成人精品福利| 日韩黄色成人| 国产啊啊啊视频在线观看| eeuss影院网站免费观看| 国产午夜视频| 牛牛在线精品视频| 亚洲精品男人| 精品日韩av| 国产激情二区| 国产精品美女一区二区三区四区| 久久99亚洲网美利坚合众国 | 国产乱xxⅹxx国语对白| 亚洲综合在线不卡| 最新超碰在线| 成人欧美日韩| 国产裸舞福利在线视频合集| 欧美韩日国产| 超碰国产在线| av资源网站在线观看| 国产精品麻豆一区二区三区| 国产一区二区三区福利| 99热在线观看免费| 狠狠干婷婷色| 成在线人视频免费视频| 国产精品一区二区婷婷| 中文字幕视频在线观看| 国产精品一区二三区| 老师我好爽再深一点的视频| 麻豆视频国产| 午夜伦全在线观看| 国产精品剧情一区二区在线观看| 国产一级电影网| 国产二区视频| 中文字幕av高清在线观看| 国产福利在线视频| 亚洲午夜久久久久中文字幕| 四虎精品视频| 国产美女在线一区二区三区| 中文字幕第一页av| 精品福利视频导航大全| gogo在线高清视频| 国产女王在线**视频 | 国产区成人精品视频| 五月天亚洲激情| 精品国产一区二区三区四区阿崩 | www.国产精品.com| 天天爱天天做色综合| 中文字幕2019第三页| 久久99精品久久久久久野外| 国产无套粉嫩白浆在线2022年| 国产黄色免费电影| 黄色在线视频观看网站| 国产成人综合亚洲欧美在| 亚洲视频在线观看不卡| 国产乱妇乱子| 青青青国产视频| 精品国产一区二区三区不卡在线| 九九99精品| 在线a人片免费观看视频| 中文字幕久热在线精品| yjizz视频网站在线播放| 91精品大全| 国产一区精品| 懂色av中文在线| 轻轻色免费在线视频| 99re6在线视频精品免费| 国产午夜精品一区理论片| 蜜桃av网站| 99re在线视频播放| 国产精品入口免费麻豆| 高清av中文在线字幕观看1| 日本一本久久| av片在线观看永久免费| 国产啊啊啊视频在线观看| 国产午夜在线| 国产丝袜精品丝袜| 最新中文字幕av专区| 国产剧情在线一区| 国产精品外围在线观看| 国产男女无套在线播放| 黄网址在线播放免费| 久久久久国产精品嫩草影院| 欧洲有码在线视频| 亚洲人在线播放| www在线播放| 狂野欧美性猛交xxxx乱大交| 欧美xxxxx性| 国产美女视频一区二区二三区| 老司机精品视频一区二区| 欧美精品小视频| 毛片视频免费观看| 久久精品无码一区二区日韩av| 超碰在线网站| 国产三区四区在线观看| 精品国产美女福利到在线不卡| 99精品老司机免费视频| wwww亚洲| 国产精品视频一区麻豆| 精品一区二区三区免费站| av亚洲男人天堂| 国产在线视精品麻豆| 国产一级在线观看| 中文国产字幕在线观看| www.操操操| 国产精品视频一区麻豆| 在线免费看黄网站| 国产麻豆一级片| 精品全国在线一区二区| 四虎成人免费观看在线网址| 丁香综合五月| av二区三区| 国产免费人人看| 中文日本在线观看| 国产字幕在线看| 樱花草在线观看www| 国产特黄在线| 老鸭窝av在线| 亚色视频在线观看| 2020亚洲男人天堂| 99热在线免费观看| av在线二区| 国产福利片在线| 天天操天天艹| 丁香在线视频| 九九热在线观看视频| www.xxx黄| 在线视频观看亚洲| 国产成人精品久久一区二区小说| av中文在线| 中文乱码字幕高清在线观看| 国产精品合集一区二区| 国产69精品久久久久孕妇国产69久久| 伊人永久在线| 在线观看中文字幕的网站| 精品美女调教视频| 91青青在线视频| 精品一区二区三区在线成人| 国产高清免费视频| 2020亚洲男人天堂| 中文字幕av网| av网站在线播放| 香蕉视频免费在线播放| www.超级碰| www555久久| 欧美日韩不卡中文字幕在线| 天天草天天干| 久久精品无码一区二区日韩av| 免费看成年人视频在线观看| 青青久在线视频免费观看| www.狠狠插| 福利视频网址导航| 国产香蕉尹人视频在线| 国产精品伦一区二区三区级视频频 | 国产中文在线| 蜜桃av网站| 99视频免费| 91亚洲天堂| 四虎免费播放| 国产伦精品一区二区三区高清版禁| 尤物视频网站在线观看| 国产成人夜间影院在线观看| 伊人222成人综合网| 青青青青在线| 国产视频精品久久| 亚洲人av在线| 国内自拍视频在线观看| 国产偷倩在线播放| 四虎在线免费视频| 国产呻吟对白刺激无套视频在线| 国产欧美日本亚洲精品一4区| 伊人色综合网| 国产一级在线| 免费看的毛片| 午夜在线视频播放| 国产va在线| 国产日韩精品在线看| 波多野结衣久久高清免费| 国产亚洲依依| 丁香花视频在线观看| 香蕉视频网站在线播放| 国产福利图片|