1. 程式人生 > >關於a標籤的點選事件觸發無效的問題

關於a標籤的點選事件觸發無效的問題

Write By Monkeyfly

以下內容均為原創,如需轉載請註明出處。

前提

  • 專案為:xxxx管理系統。在該系統中,可以通過點選左側的選單(導航欄)來實現右邊內容的切換。而且內容區的頁面都是巢狀在 iframe 框架中的。
  • 前提: iframe 巢狀的某個頁面中有一個 <a> 標籤。如:<a href="javascript:;">更多>></a>
  • 要實現的效果是:點選 <a> 標籤,在右側內容區新開啟一個選項卡,即跳轉到指定的某個頁面。
  • 這個操作相當於,在 <a> 標籤的點選事件中進行了這樣的處理:相當於直接點選了要跳轉頁面所對應的 側邊選單欄中的某一項子選單
    ,然後就會在 tab 欄中新開啟一個頁面,而且該頁面是巢狀在 iframe 中的。

注:為了說明問題,以下展示的系統圖片均為網上下載,然後自己用PS處理過的。

具體操作如下圖所示:

  • 假設 “交易資訊” 頁面中存在一個 a 標籤,它的文字內容為“更多>>”。
<a href="javascript:;" id="more">更多>></a>
  • 當點選“更多>>”時,當前頁面需要跳轉到“管理員日誌”的頁面。

這裡寫圖片描述

說明:當點選“更多>>”時,相當於點選了 側邊選單欄中的子選單項 “管理員日誌”,然後打開了一個新的標籤頁。


這裡寫圖片描述

實現方法

先看一下 HTML 佈局:

//寫之前看了一下專案原始碼,發現該系統使用的是 “metisMenu側邊欄外掛” 實現的側邊導航欄的製作。
//我對佈局大致進行了還原,如下所示:

<ul class="metismenu" id="menu">
     <li class="active">
        <a href="#" aria-expanded="true">管理員管理</a>
        <ul aria-expanded="true">
            <li><a
href="/adminList.html" id="adminList">
管理員列表</a></li> <li><a href="/adminLog.html" id="adminLog">管理員日誌</a></li> </ul> </li> <li> <a href="#" aria-expanded="false">交易管理</a> <ul aria-expanded="false"> <li><a href="/tradeInfo.html">交易資訊</a></li> </ul> </li> ... </ul>

jQuery程式碼部分:

//假定這是“交易資訊”頁面(tradeInfo.html)中的一個跳轉連結
<a href="" id="more">更多>></a>
//首先遮蔽它的 href 屬性,即預設的跳轉連結,如下:
<a href="javascript:;" id="more">更多>></a>
//然後,為它新增點選事件
$("#more").onclick(function(){
    //疑問:點選事件中應該如何去寫呢?
    //方法:首先,肯定要找到,跳轉到“管理員日誌”頁面所對應的那個子選單項(即<a>管理員日誌</a>標籤),然後觸發它的點選事件即可。

});

重點來了:如何在 iframe 框架巢狀的頁面中,獲取到側邊導航欄中的某個元素呢?
分析

  • 首先,對於側邊導航欄來說,它本身也是巢狀在 iframe 框架中的一個頁面。
  • 其次,在父級視窗window下,不考慮其他情況,假設只存在兩個iframe
    • 那麼就可以肯定:一個 子iframe 為側邊導航欄,另外一個 子iframe 為右側的內容顯示區。
  • 現在,我們知道了它們之間的關係,那此時要做的就是:在父級視窗的環境下,我們必須要從其中一個子iframe巢狀的頁面中,找到另一個子iframe所巢狀的頁面中指定的某個元素。
    • 簡單來說就是:兩個子iframe分別嵌套了兩個不同的頁面,而且這兩個頁面之間要進行通訊。
  • 現在問題簡化了,那麼接下來我們應該怎麼去做呢?

頁面演示和說明

(下面要做的就是:在其中一個 子iframe 巢狀的頁面中,找到 另一個子iframe 所巢狀頁面 內部的某個指定元素。)

注:

  • 因上面的圖片不好進行網頁結構的說明演示,故舍棄了。
  • 在這裡引用了群裡某個大神自己搭建的一個後臺管理系統,僅供演示說明。

1.頁面整體結構如下圖所示:

該系統的主頁面總共分為4個部分:頭部區域、左側導航欄區域、右側內容區域以及底部區域。

這裡寫圖片描述

頭部區域
頭部的功能區由一個ul列表組成。
這裡寫圖片描述

左側導航欄區域

  • 左側的選單欄是由一個ul列表巢狀dl列表組成。
  • 一級選單由一個ul列表組成,一級選單的每一項對應每一個li元素。
  • 二級選單是由一個dl列表組成的,二級選單的每一項對應每一個dd元素。
  • 而每個dd元素中又包含了一個a標籤,用於選擇某個選單項時,在右側內容區開啟一個新的選項卡。
    這裡寫圖片描述

右側內容區域

  • 右側內容區由兩部分組成:tab選項卡(對應頁面中的tab-title)、選項卡下面的內容區(對應頁面中的tab-content)。
  • 內容區域由多個div(對應頁面中的tab-item)組成,每個 tab-item 都對應每一個開啟的選項卡。
  • 在每個 tab-item 中,都存在一個 iframe 內聯框架。而每個 iframe 框架中就嵌入了每個選項卡所對應的頁面。
  • 開啟多個選項卡,頁面就會生成多個 tab-item,也就出現了多個 iframe。
  • 只不過同一時間只會展示一個選項卡,所以同時只能有一個iframe存在,其他沒有被關閉的選項卡對應的 iframe 都被隱藏了。

這裡寫圖片描述

底部區域
這裡寫圖片描述

2.所要實現的功能如下圖所示:
這裡寫圖片描述

這裡寫圖片描述

3.頁面結構的分析如下圖所示:

這裡寫圖片描述

說明:由於該系統的佈局和我專案中的不太一樣,所以在查詢元素的步驟上會有一些差異。

頁面佈局上的唯一區別:

  • my:側邊欄的部分並不在父視窗中,它是巢狀在了一個iframe中。這就涉及到要跨越 兩個iframe 進行查詢元素。就是多了一步 進入iframe 的操作而已。即子iframe之間的通訊。【稍複雜】
  • other:側邊欄的部分存在於父視窗中。所以這裡只有 子iframe和父視窗 之間的通訊,少了一層關係。【簡單】

實現步驟

具體步驟如下:(先來演示簡單的)

過程:子iframe → 父視窗環境 → 進入父視窗的文件 → 利用CSS選擇器,通過DOM查詢找到指定元素 → 呼叫該元素的點選事件

1.子iframe → 父視窗環境 【注:js部分用的是jQuery的寫法。】

//因為邏輯程式碼都在 子iframe中寫的,所以此時的 window 物件獲取到的是 子iframe所在的內聯框架的視窗,即子視窗物件。
window
//因此,window.parent獲取到的就是 父視窗物件。
/*知識點:Window物件的 parent屬性 返回當前視窗的父視窗。*/
window.parent

2.父視窗環境 → 進入父視窗的文件

//切記:必須進入父視窗的文件中,然後才能進行DOM操作。
/*知識點:獲取到頁面的window.document物件後,即可訪問DOM元素。*/
window.parent.document

3.進入父視窗的文件 → 利用CSS選擇器,通過DOM查詢找到指定元素

//進入父視窗的文件後,然後進行元素的查詢(注:查詢的id都是自己隨便編的,根據自身情況進行改寫即可)
$(window.parent.document).find("#nav_menu").find("a#article_list");

4.利用CSS選擇器,通過DOM查詢找到指定元素 → 呼叫該元素的點選事件

//找到該元素後,呼叫它的點選事件即可。(注:此時的點選事件是不會生效的,原因我會在下面詳解。)
$(window.parent.document).find("#nav_menu").find("a#article_list").click();

具體步驟如下:(再來演示覆雜的)

過程:子iframe → 父視窗環境 → 進入父視窗的文件 → 找到側邊欄對應的子iframe → 進入側邊欄子視窗的環境
→ 進入側邊欄子視窗的文件 → 利用CSS選擇器,通過DOM查詢找到指定元素 → 呼叫該元素的點選事件

1.子iframe → 父視窗環境 【注:js部分用的是jQuery的寫法。】

//因為邏輯程式碼都在 子iframe中寫的,所以此時的 window 物件獲取到的是 子iframe所在的內聯框架的視窗,即子視窗物件。
window
//因此,window.parent獲取到的就是 父視窗物件。
/*知識點:Window物件的 parent屬性 返回當前視窗的父視窗。*/
window.parent

2.父視窗環境 → 進入父視窗的文件

//切記:必須進入父視窗的文件中,然後才能進行DOM操作。
/*知識點:獲取到頁面的window.document物件後,即可訪問DOM元素。*/
window.parent.document

3.進入父視窗的文件 → 找到側邊欄對應的子iframe

//切記:必須進入父視窗的文件中,然後才能進行DOM操作。
/*知識點:獲取到頁面的window.document物件後,即可訪問DOM元素。*/
//(注:查詢的id都是自己隨便編的,根據自身情況進行改寫即可)
$(window.parent.document).find("iframe#articleList");//jQuery獲取方式
window.parent.document.querySelector("iframe#articleList");//原生js獲取方式

4.找到側邊欄對應的子iframe → 進入側邊欄子視窗的環境

//問題來了:找到了對應的子iframe,如何進入iframe框架內的視窗環境呢?
/*知識點:Frame/IFrame物件 的 contentWindow 屬性,可以獲取到指定的frame或者iframe所在的window物件*/
$(window.parent.document).find("iframe#articleList")[0].contentWindow;//jQuery獲取方式
window.parent.document.querySelector("iframe#articleList").contentWindow;//原生js獲取方式

5.進入側邊欄子視窗的環境 → 進入側邊欄子視窗的文件

//切記:必須進入子視窗的文件中,然後才能進行DOM操作。
/*知識點:獲取到頁面的window.document物件後,即可訪問DOM元素。*/
$($(window.parent.document).find("iframe#articleList")[0].contentWindow.document);//jQuery獲取方式
window.parent.document.querySelector("iframe#articleList").contentWindow.document;//原生js獲取方式

6.進入側邊欄子視窗的文件 → 利用CSS選擇器,通過DOM查詢找到指定元素

//進入父視窗的文件後,然後進行元素的查詢(注:查詢的id都是自己隨便編的,根據自身情況進行改寫即可)
$($(window.parent.document).find("iframe#articleList")[0].contentWindow.document).find("#nav_menu").find("a#article_list");//jQuery獲取方式
window.parent.document.querySelector("iframe#articleList").contentWindow.document.getElementById("nav_menu").querySelector("a#article_list");//原生js獲取方式

7.利用CSS選擇器,通過DOM查詢找到指定元素 → 呼叫該元素的點選事件

//找到該元素後,呼叫它的點選事件即可。(注:此時使用jQuery方式獲取元素的點選事件是不會生效的,原因我會在下面詳解。)
$($(window.parent.document).find("iframe#articleList")[0].contentWindow.document).find("#nav_menu").find("a#article_list").click();//jQuery獲取方式【無效】
window.parent.document.querySelector("iframe#articleList").contentWindow.document.getElementById("nav_menu").querySelector("a#article_list").click();//原生js獲取方式【有效】

關於a標籤點選事件無效的說明

  • 因為a標籤上只存在一個href屬性,並沒有給它新增點選事件。所以獲取到該元素之後,直接呼叫它的點選事件是不會生效的。
  • 那應該怎麼做呢?
  • 經過百度之後,找到了答案:
    • HTML DOM物件的 click()方法,用於在 DOM元素 上模擬一次滑鼠單擊事件。
    • click()方法:模擬滑鼠點選元素。該方法用於執行點選元素動作上,就像使用者手動點選一樣。
    • 用法:HTMLElementObject.click()
    • 注意:HTML原生DOM物件的click()事件和jQuery的click()事件是有本質區別的。
    • 區別:一個是模擬使用者的點選事件;一個是觸發 click 事件。

總結

  • 所以,如果想要呼叫a標籤的點選事件:
    必須通過呼叫原生DOM物件的click()方法來實現模擬使用者的點選事件,而非通過呼叫jQuery物件的click()方法來實現。
  • 因此,將上面利用jQuery click()方法,呼叫a元素點選事件的實現方式做以改變即可:
//HTML部分
<a href="/media/media.html" class="nav-item" data-navid="1">分頁媒體庫</a>
//JS部分(修改前)
$($(window.parent.document).find("iframe#articleList")[0].contentWindow.document).find("#nav_menu").find("a#article_list").click();//jQuery獲取方式【無效】
//JS部分(修改後)
$($(window.parent.document).find("iframe#articleList")[0].contentWindow.document).find("#nav_menu").find("a#article_list")[0].click();//原生JS獲取方式【有效】

結束語

  • 為了說明問題的本質,為了能讓更多的人理解其中的原理,為了能讓更多的人看清楚,看明白。
  • 本篇博文用了大量的篇幅來對頁面結構和頁面之間的通訊進行了詳細說明,可能內容有些偏多,希望大家可以耐心看完。
  • 如果發現文章中有存在錯誤的地方,歡迎大家批評指正。
  • 至此,所有的內容到這裡就結束了。