主頁 > 企業開發 > jQuery 原始碼分析(十九) DOM遍歷模塊詳解

jQuery 原始碼分析(十九) DOM遍歷模塊詳解

2020-09-14 10:55:23 企業開發

jQuery的DOM遍歷模塊對DOM模型的原生屬性parentNode、childNodes、firstChild、lastChild、previousSibling、nextSibling進行了封裝和擴展,用于在DOM樹中遍歷父元素、子元素和兄弟元素,

可以通過jQuery的實體來訪問,方法如下:

  •   parent()                  ;獲取匹配元素的父元素                
  •   parents(selector)           ;獲取匹配元素的所有祖先元素                                    ;selector用于過濾查找的元素,如果為空則獲取所有的祖先元素            
  •   parentsUntil(until,selector)    ;獲得當前匹配元素集合中每個元素的祖先元素,直到遇到until元素        
  •   next()                     ;獲取匹配元素之后緊挨著的兄弟元素,沒有則回傳undefined
  •   nextAll(selector)               ;獲取匹配元素之后緊挨著的所有兄弟元素             
  •   nextUntil(until,selector)       ;獲取匹配元素之后緊挨著的所有兄弟元素,直到遇到until元素 
  •   prev()                    ;獲取匹配元素之前緊挨著的兄弟元素,沒有則回傳undefined
  •   prevAll(selector)              ;獲取匹配元素之前緊挨著的所有兄弟元素             
  •   prevUntil(until,selector)        ;獲取匹配元素之前緊挨著的所有兄弟元素,直到遇到until元素     
  •   siblings(selector)            ;獲取匹配元素的所有兄弟元素,如果指定了selector則只獲取該型別的元素 
  •   children(selector)           ;獲取匹配元素的子元素,不包括文本節點和注釋節點         
  •   contents()                  ;獲取匹配元素的子元素,包括文本節點和注釋節點 

舉個栗子:

 writer by:大沙漠 QQ:22969969

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Document</title>    <script src="http://libs.baidu.com/jquery/1.11.1/jquery.min.js"></script></head><body>    <div>        <h1>Hello World!</h1>        <p>123</p>        <span>123</span>            </div>    <script>        console.log( $('p').parent() )            //獲取p元素的父元素        console.log( $('p').prev() )              //獲取p元素之前緊挨的兄弟元素        console.log( $('p').next() )              //獲取p元素之后緊挨的兄弟元素        console.log( $('p').siblings() )          //獲取p元素的所有兄弟元素        console.log( $('div').children() )        //獲取div的所有子元素,不包括文本節點和注釋節點        console.log( $('div').contents() )        //獲取div的所有子元素,包括文本節點和注釋節點    </script></body></html>

輸出如下:

 對應栗子里的每一個輸出,分別輸出

  • p元素的父節點
  • p元素的上一個兄弟元素
  • p元素的下一個兄弟元素
  • p元素的所有兄弟元素
  • div元素過濾掉文本節點和空白節點的子節點
  • div元素包括文本節點和空白節點的子節點

回傳的都是一個jQuery物件,非常的好用,操作DOM時都會用到這幾個方法

 

原始碼分析


 jQuery對于DOM遍歷模塊的實作是基于三個工具函式實作的

  • $.dir(elem, dir, until)       ;從elem元素開始,查找dir方向(可以是:parentNode、nextSibling或previousSibling)上的所有元素,如果在查找程序中遇到匹配引數until的元素,則查找終止
  • $.nth(cur, result, dir, elem)  ;從cur元素出發,查找dir方向(parentNode、nextSibling或previousSibling)上的第result個元素
  • $.sibling(n, elem)       ;負責查找一個元素之后的所有兄弟元素,包括起始元素,但不包括引數elem,n是查找的起始元素,包含在結果集中,elem是可選的DOM元素,不包含在回傳結果中,

舉個栗子:

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Document</title>    <script src="http://libs.baidu.com/jquery/1.7.1/jquery.min.js"></script></head><body>    <div>        <h1>Hello World!</h1>        <p>123</p>        <span>123</span>            </div>    <script>            var h1 = document.getElementsByTagName('h1')[0],          //分別獲取h1、p、span元素的節點參考            p = document.getElementsByTagName('p')[0],            span = document.getElementsByTagName('span')[0];        console.log( $.dir(h1,'parentNode') )                     //列印h1的所有祖先節點                    console.log( $.nth(h1,3,'nextSibling') )                  //獲取h1之后的第二個節點        console.log( $.sibling(h1,h1) )                           //獲取h1的所有兄弟元素,默認獲取包括自身在內的元素,引數2也傳入h1表示排除h1元素    </script></body></html>

輸出如下:

輸出三行,分別對應h1的所有祖先節點、h1之后的第二個子節點和h1的所有兄弟元素,和DOM樹中也是對應的,

對于$.dir、$.nth和$.sibling來說,它的實作如下:

jQuery.extend({    dir: function( elem, dir, until ) {        //從elem元素開始,查找dir方向(可以是:parentNode、nextSibling或previousSibling)上的所有元素,如果在查找程序中遇到匹配引數until的元素,則查找終止,        var matched = [],            cur = elem[ dir ];                    //cur表示下一個元素,根據引數dir不同,可能是父元素、前一個兄弟元素 或者 后一個兄弟元素        while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {    //如果下一個元素存在 且 不是document物件(nodeType等于9) 則繼續判斷括號里的陳述句,否則跳出回圈  括號內:如果沒有傳入until引數,或者傳入了until引數并且當前元素不是Element節點(屬性nodeType等于1)    或者 傳入了until引數且當前引數是Element節點且該元素不匹配引數until 則進行回圈            if ( cur.nodeType === 1 ) {                    //如果cur是元素節點                matched.push( cur );                        //存盤到陣列matched中            }            cur = cur[dir];                                //獲取下一個方向上的元素        }        return matched;                                //回傳找到了的Element節點陣列,    },    nth: function( cur, result, dir, elem ) {    //從cur元素出發,查找dir方向(parentNode、nextSibling或previousSibling)上的第result個元素        result = result || 1;        var num = 0;                                //當前查找的元素序號        for ( ; cur; cur = cur[dir] ) {                    //從起始元素cur觸發,沿著方向dir迭代遍歷,只要cur元素存在則一直查找,直到查找該方向上的第result個Element節點            if ( cur.nodeType === 1 && ++num === result ) {    //如果cur是一個元素節點,則num+1,此時如果num等于result,則表示查找到該元素了,則跳出回圈                break;            }        }        return cur;                                        //回傳查找到的cur元素,    },    sibling: function( n, elem ) {                //負責查找一個元素之后的所有兄弟元素,包括起始元素,但不包括引數elem,n是查找的起始元素,包含在結果集中,elem是可選的DOM元素,不包含在回傳結果中,        var r = [];        for ( ; n; n = n.nextSibling ) {                //從起始元素n觸發,迭代遍歷其后的所有兄弟元素            if ( n.nodeType === 1 && n !== elem ) {            //如果該兄弟元素是元素節點且不等于引數elem則被放入陣列r中,                r.push( n );            }        }        return r;                                        //回傳存放了找到的Element節點的陣列r    }});

也就是對parentNode、childNodes、firstChild、lastChild、previousSibling、nextSibling這些原生DOM操作的一些封裝

我們通過jQuery實體可以訪問的方法的實作如下:

jQuery.each({    parent: function( elem ) {                        //回傳匹配元素的父元素        var parent = elem.parentNode;        return parent && parent.nodeType !== 11 ? parent : null;    //如果父元素存在且不是檔案碎片元素,則回傳該父元素,否則回傳null    },    parents: function( elem ) {                        //回傳匹配元素的所有祖先元素        return jQuery.dir( elem, "parentNode" );    },    parentsUntil: function( elem, i, until ) {        //獲得當前匹配元素集合中每個元素的祖先元素,直到遇到until元素        return jQuery.dir( elem, "parentNode", until );    },    next: function( elem ) {                        //獲取匹配元素之后緊挨著的兄弟元素            return jQuery.nth( elem, 2, "nextSibling" );    },    prev: function( elem ) {                        //獲取匹配元素之前緊挨著的兄弟元素        return jQuery.nth( elem, 2, "previousSibling" );    },    nextAll: function( elem ) {                        //獲取匹配元素之后緊挨著的所有兄弟元素            return jQuery.dir( elem, "nextSibling" );    },    prevAll: function( elem ) {                        //獲取匹配元素之前緊挨著的所有兄弟元素        return jQuery.dir( elem, "previousSibling" );    },    nextUntil: function( elem, i, until ) {            //獲取匹配元素之后緊挨著的所有兄弟元素    ,直到遇到匹配元素until為止        return jQuery.dir( elem, "nextSibling", until );    },    prevUntil: function( elem, i, until ) {            //獲取匹配元素之前緊挨著的所有兄弟元素    ,直到遇到匹配元素until為止        return jQuery.dir( elem, "previousSibling", until );    },    siblings: function( elem ) {                    //獲取匹配元素的所有兄弟元素        return jQuery.sibling( elem.parentNode.firstChild, elem );    },    children: function( elem ) {                    //獲取匹配元素的子元素        return jQuery.sibling( elem.firstChild );    },    contents: function( elem ) {                    //獲取匹配元素的子元素,包括文本節點和注釋節點        return jQuery.nodeName( elem, "iframe" ) ?            elem.contentDocument || elem.contentWindow.document :            jQuery.makeArray( elem.childNodes );    }}, function( name, fn ) {                            //模板函式,用于呼叫對應的遍歷函式查找DOM元素,然后執行過濾、排序、和去重操作         name是每個函式名,fn是對應的值(也就是函式)    jQuery.fn[ name ] = function( until, selector ) {        //定義模版函式,真正是在這里定義的,它接收兩個引數 until:選擇器運算式,用于指示查找停止的位置,selector:選擇器運算式,用于過濾找到的元素        var ret = jQuery.map( this, fn, until );                //呼叫方法jQuery.map()遍歷當前匹配元素集合,對每個元素呼叫遍歷函式fn,并將遍歷函式fn的回傳值放入一個新的陣列ret中,        if ( !runtil.test( name ) ) {                        //如果遍歷函式名不以'Until'結尾的,則最多只有一個引數            selector = until;                                    //修正引數selector為until        }        if ( selector && typeof selector === "string" ) {    //如果設定了引數selector 且selector是一個字串            ret = jQuery.filter( selector, ret );                //則呼叫jQuery.filter()對陣列ret中的DOM元素逐個過濾,最終只保留匹配選擇器運算式selector的元素,        }        ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;        if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {        //排序            ret = ret.reverse();                        }        return this.pushStack( ret, name, slice.call( arguments ).join(",") );    //創建一個jQuery物件并回傳    };});

實作就是通過$.each()遍歷一個物件,依次執行引數2這個函式,該函式會在$.fn上依次掛載每個介面,使用$.map()工具方法它會依次執行fn函式,進行一些過濾去重后最后呼叫$.pushStack()將陣列轉換為一個jQuery物件,這里理解起來有點難度,需要多理一下代碼,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/34148.html

標籤:jQuery

上一篇:下拉框一級樹形多選 框

下一篇:D3 Scale functions

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more