在探讨C/S模式的Tab之前,我们先总结一下B/S模式的Tab通常是什么样的。web中常见的tab设计通常是用于分节展示大量信息以提高页面空间的利用率,而且这些信息通常是静态的,或者交互比较简单。通过ajax动态加载tab内容的技术也是为这种应用场景设计的。

随着Web技术的发展,越来越多的桌面应用都在向Web应用转型。在这个过程中,很多C/S模式的应用场景不可避免的会被移植到Web中。但是B/S模式相对较弱的交互性决定了某些移植很难实现或者效果不好。C/S模式的Tab设计就是其中之一。

所谓C/S模式的Tab实际上是为了在不需要打开多个应用的情况下,可以同时对多个对象进行操作,以提高工作效率。这个应用场景在往B/S移植的过程中,如果沿用B/S常用的tab技术,通过ajax动态加载tab内容,就会有一些技术难点:

  • 在B/S的架构中,同一类型的tab页通常是对应的同一个物理页面,例如订单A和订单B的的tab页实际上都是对应的order.php这个页面,只不过请求的GET参数不一样而已。这样如果同时加载了订单A和订单B的tab页,那么这两个页面的html和js很可能发生冲突。
  • 我们需要用一种标识来区别不同的tab页,并且避免重复打开同一个tab页。例如,在订单A已经被打开的情况下,如果试图再打开订单A,那么订单A的tab应该被激活,而不是再打开一个订单A。
  • 如果打开的tab数量较多,或者tab页中的交互复杂、内容很多,浏览器就很容易出现性能问题,速度变的很慢。
  • 还有很多潜在的、琐碎的问题随时可能让我们抓狂。在这点上,我是有惨痛教训的……

其实解决上面这些问题的方式是很多的。经过一些尝试、失败和总结,我选择了一种现代结合复古的方式:动态生成iframe,并通过iframe的src属性来区分不同的tab。采用这种方案之后,上面难题都迎刃而解,唯一的不足就是tab子页和主页间的交互会变得比较复杂。请猛击这里看demo。这个demo模拟了一个查看、修改订单的应用场景,主要实现了这些功能:

  1. 添加tab的时候,动态生成一个iframe。并且在tab切换的时候,所有iframe都不会刷新。
  2. iframe的高度自适应内容的高度。
  3. 在尝试打开一个已经存在的tab的时候,会激活这个tab,不会重复打开相同的tab。
  4. tab可以被关闭,并且关闭的时候tab对应的iframe会被移除。

下面我们就一步一步的实现上面的功能。

第一步:编写demo的框架

这个demo用到了jquery和jquery的ui库,文件结构如图:

其中:

  • index.html是demo的首页。
  • order.php就是订单的详细页面,每个订单详情tab都是加载的这个页面。
  • index.css是首页的样式表。
  • index.js是首页的js脚本。

由于篇幅的限制,这里就不贴代码了,demo的源代码在文章最后可以下载。

第二步:初始化jquery tab

现在我们可以开始编写index.js了。首先是初始化tab:

//初始化tab
$( "#tabs").tabs({tabTemplate:'<li><a href="#{href}">#{label}</a><a class="close" href="#">x</a></li>',cache:true})
.bind("tabsadd", function( event, ui ) {$(this ).tabs( "select", "#" +ui.panel.id );
});

初始化参数中的tabTemplate是为后面的关闭tab做准备。这里还绑定了一个tabsadd的事件处理函数,作用是在添加tab之后立即选中新增的tab。

第三步:动态生成iframe

如果现在打开页面,只能看到订单列表一个tab,下面我们让列表中的连接被点击之后,添加一个新tab显示对应订单的详情:

//点击添加tab页
$( ".list a" ).click( function( e ) {e.preventDefault();var href = $( this ).attr( "href");var orderid = href.substring( href.indexOf( "-" ) + 1);var tabid = "order-" +orderid;var url = "order.php?orderid=" +orderid;var label = "订单详情-" +orderid;addTab( tabid, url, label );
});//添加tab的接口
functionaddTab( id, url, label ) {var mainTab = $( "#tabs");var panel = $( "<div/>").attr({"id": id}).appendTo( mainTab );mainTab.tabs("add", "#" +id, label );$("<iframe/>").attr({"frameBorder": "0","scrolling": "no","allowTransparency": "true","src": url}).css({"width": "100%","height": "100px"}).load(function() {var iframe = $( this);iframe.height( iframe.contents().find("body").height());}).appendTo( panel );
}

上面的代码中,我们编写了一个方法作为添加tab的通用接口。在点击某一个订单链接的时候,我们会调用这个添加tab的接口,按顺序做这几件事:

  1. 生成一个div,作为jquery tab的panel,也就是iframe的容器。
  2. 调用jquery tab的接口新增一个tab指向刚才的div,并选中这个tab(刚才绑定的tabsadd事件)。
  3. 创建并初始化一个iframe,然后将它添加到刚生成的div里面。其中,在初始化的时候我们给iframe添加了一个load事件的处理函数,用来让iframe自适应内容的高度。

第四步:防止重复打开tab

现在如果多次点击订单列表中的同一个链接,我们会打开多个相同的tab。为了避免这种情况发生,我们需要在添加tab之前,通过iframe的src判断这个tab是否已经被打开,如果已经被打开,则选中这个tab(4行至15行):

//添加tab的接口
functionaddTab( id, url, label ) {var mainTab = $( "#tabs");var added = false;$("iframe", mainTab ).each( function( i ) {var src = this.src.substring( this.src.lastIndexOf( "/" ) + 1);if ( src ==url ) {added= $( this);}});if( added ) {mainTab.tabs("select", "#" + added.parent().attr( "id"));return;}var panel = $( "<div/>").attr({"id": id}).appendTo( mainTab );mainTab.tabs("add", "#" +id, label );$("<iframe/>").attr({"frameBorder": "0","scrolling": "no","allowTransparency": "true","src": url}).css({"width": "100%","height": "100px"}).load(function() {var iframe = $( this);iframe.height( iframe.contents().find("body").height());}).appendTo( panel );
}

第五步:关闭tab

最后我们让tab上的关闭链接发挥作用。实现这个功能通常的思路是,在每次添加tab的时候(tabsadd事件)绑定关闭tab的处理函数。但是这里我们会使用jquery 1.3中的一个新特性——live event来实现这个功能:

//动态绑定关闭tab的事件
$( ".ui-tabs-nav a.close" ).live( "click", function( e ) {e.preventDefault();var index = $( ".ui-tabs-nav li" ).index( $( this).parent());$("#tabs" ).tabs( "remove", index );
});

简单的说,live event就是预先给某些目前DOM中可能不存在,但是未来会被动态加入到DOM中的元素绑定事件处理函数。想了解更多关于live event的信息,请参考jquery的文档。

至此,demo中的所有功能我们都已经实现了。这种实现C/S模式tab的方案,就目前来说,我觉得不是完美的,但却是可行性最强的。现实的开发中可能出现的一些其他常用需求,比如加载iframe的loading效果,实现起来都会比较容易。

转载于:https://www.cnblogs.com/longhs/p/4529477.html

在Web中实现C/S模式的Tab相关推荐

  1. Web中的积累:外观模式 Facade

    摘要: 原创出处: http://www.cnblogs.com/Alandre/ 泥沙砖瓦浆木匠 希望转载,保留摘要,谢谢! 壹 前言 目测好久没写文章了,距离上一篇文章也有二十多天.我是怎么了?哈 ...

  2. Java开发web的几种开发模式

    Java开发web的几种开发模式 Java Web开发方案有多种可供选择,这里列举一些经典的开发模式进行横向比较,为Java Web的开发模式选择提供参考.除此之外还有好多方案(如Tapestry和W ...

  3. 5.在MVC中使用泛型仓储模式和工作单元来进行增删查改

    原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/crud-operations-using-the-generic-repository-pat ...

  4. 深入学习Web Service系列----异步开发模式

    概述 在本篇随笔中,通过一些简单的示例来说一下Web Service中的异步调用模式.调用Web Service方法有两种方式,同步调用和异步调用.同步调用是程序继续执行前等候调用的完成,而异步调用在 ...

  5. 在C#代码中应用Log4Net(四)在Winform和Web中捕获全局异常

    毕竟人不是神,谁写的程序都会有bug,有了bug不可怕,可怕的是出错了,你却不知道错误在哪里.所以我们需要将应用程序中抛出的所有异常都记录起来,不然出了错,找问题就能要了你的命.下面我们主要讨论的是如 ...

  6. web中各种命令注入的检测和利用二

    0x00 前言 我们都知道在web 中有着各种数据注入攻击,其中有SQL注入.命令注入.XML注入等等.在平时我们渗透测试的任务中,如何快速检测和利用这些注入的漏洞,以下是一些注入命令总结 0x01 ...

  7. JAVA web中的一点东西

    参考文献: http://m.blog.csdn.net/article/details?id=45151569 http://www.cnblogs.com/goody9807/archive/20 ...

  8. 关于web中的颜色表示方法,你知道多少?

    前言 想要表示web中的各种颜色,大家首先想到的大概就是用十六进制或者RGB来表示.但在实际web中,是远不止这两种的.今天这篇文章就和大家聊一聊,在web中颜色的各种表示方法. 以如下代码为例,大家 ...

  9. 使用 Internet Explorer 驱动程序在 Microsoft Edge 中自动执行 IE 模式

    使用 Internet Explorer 驱动程序在 Microsoft Edge 中自动执行 IE 模式 项目 2022/06/30 1 个参与者 如果拥有业务关键型旧版网站或应用,则可能需要在 M ...

最新文章

  1. 2022-2028年中国氨基酸表面活性剂行业研究及发展前瞻报告
  2. 在Powerpoint中插入Flash的方法
  3. Visual Studio Code (VScode)支持哪些编程语言
  4. C语言 | 基于51单片机实现MPU6050的卡尔曼滤波算法(代码类2)
  5. php反序列化绕过,【技术分享】PHP反序列化漏洞
  6. 牛!Python 全栈必备的 150 个实战案例,一次性获得!
  7. 前端JavaScript 常见的报错及异常捕获与处理方法
  8. 出去转了一转,便利店......
  9. TimeLine下载地址
  10. Kafka从上手到实践 - 实践真知:搭建单机Kafka | 凌云时刻
  11. JSON格式错误报JSON parse error:
  12. 网易邮箱发送邮件显示服务器错误,Outlook Express收发163.com邮件( 服务器错误: 553)...
  13. 2023南京师范大学计算机考研信息汇总
  14. 软件工程自学笔记一(基础篇)
  15. vue判断什么手机打开网页及是否用QQ浏览器或者微信浏览器打开
  16. 斐讯n1盒子装网易音乐命令版
  17. CentOS 6.5安装Nvidia显卡驱动
  18. 塞班微信登录显示服务器繁忙,塞班系统彻底告别 已无法登陆QQ/微信
  19. Oceanbase 扩容TPC-H测试
  20. 7-4 大炮打蚊子 (20分)__C++

热门文章

  1. C/C++:Windows编程—代码获取本地所有网卡信息(网卡描述,IP地址,子网掩码,MAC地址)
  2. Linux系统编程:lseek扩展文件大小失败原因分析
  3. Linux系统编程:pipe匿名管道的使用,实现linux命令下管道命令
  4. 20165307《网络对抗技术》Exp1 PC平台逆向破解
  5. Python 面向对象(二)
  6. mybatis中#{}和${}传参的区别
  7. ListView setOnItemClickListener无效
  8. 生产者/消费者模式(一)
  9. 和 Python 2.x 说再见!
  10. 2.14情人节,程序员该如何绝地反击?