关于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 所嵌套页面 内部的某个指定元素。)

注:

  • 因上面的图片不好进行网页结构的说明演示,故舍弃了。
  • 在这里引用了群里某个大神自己搭建的一个后台管理系统,仅供演示说明。

具体点此查看→Sunless CMS

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标签点击事件无效的说明

参考资料1:jquery click()方法模拟点击事件对a标签不生效的解决办法
参考资料2:HTML DOM element.click()方法; 模拟鼠标点击元素

  • 因为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获取方式【有效】

结束语

  • 为了说明问题的本质,为了能让更多的人理解其中的原理,为了能让更多的人看清楚,看明白。
  • 本篇博文用了大量的篇幅来对页面结构和页面之间的通信进行了详细说明,可能内容有些偏多,希望大家可以耐心看完。
  • 如果发现文章中有存在错误的地方,欢迎大家批评指正。
  • 至此,所有的内容到这里就结束了。
  • 11
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值