一、前言
1.什么是Tab选项卡
选项卡(Tab)是一种常见的用户界面元素,用于在一个容器中显示多个内容页面。每个选项卡通常由一个标签和一个对应的内容区域组成。
当用户点击选项卡的标签时,相应的内容区域将显示出来,而其他选项卡的内容区域则隐藏起来。这样用户可以通过点击不同的选项卡来在不同的页面之间进行切换,从而提供更好的用户体验。
在网页开发中,实现选项卡通常有多种方法,如使用HTML、CSS和JavaScript来手动编写代码,或者使用现有的选项卡插件/库来简化开发过程。常见的选项卡插件/库包括Bootstrap的Tab插件、jQuery UI的Tabs组件等。
通过选项卡,用户可以在一个页面中方便地切换不同内容,这在许多应用场景中都非常有用,例如网页导航菜单、设置面板、多标签浏览器等。选项卡的外观和交互方式可以根据设计需求和用户体验进行定制。
tab效果展示:
2.什么是iframe标签
iframe(内嵌框架)是HTML中的一个标签,用于在网页中嵌入另一个页面或文档。
通过使用iframe标签,可以在网页中创建一个独立的内联框架,用于显示来自不同源或同一源的外部内容。这个嵌入的页面可以是其他网页、视频、地图、广告等等。
iframe标签通常包含以下属性:
- src:指定要加载的内容的URL。
- width:指定`iframe`的宽度。
- -height:指定`iframe`的高度。
- frameborder:指定是否显示边框。
- scrolling:指定是否显示滚动条。
示例代码如下:
<iframe src="http://www.example.com" width="500" height="300" frameborder="0" scrolling="auto"></iframe>
需要注意的是,使用iframe标签时,被嵌入的内容将在一个单独的框架中显示,与父页面有一定的隔离性。这使得iframe非常有用,例如在网页中嵌入第三方内容、显示广告、集成其他网页应用等。但同时也需要注意安全性和设计上的考虑,避免滥用iframe可能引发的安全风险和用户体验问题。
3.使用iframe标签
当使用iframe标签时,您需要指定要嵌入的内容的URL或源文件,并定义相应的属性。下面是一个使用`iframe`标签的示例:
<!DOCTYPE html> <html> <head> <title>嵌入页面示例</title> </head> <body> <h1>主页面</h1> <iframe src="http://t.csdn.cn/ommMR" width="800" height="600" frameborder="0" scrolling="auto"></iframe> <p>这是主页面中的其他内容。</p> </body> </html>
在这个示例中,
iframe
标签嵌入了来自"http://t.csdn.cn/ommMR"的网页。宽度设置为800像素,高度设置为600像素。frameborder
属性设置为0以隐藏边框,scrolling
属性设置为"auto"以根据内容是否超出框架显示滚动条。请注意,使用
iframe
标签时需要确保嵌入的内容是可信的,并且遵循安全性最佳实践,以防止潜在的安全风险。效果演示:
二、案例实现
1.需求分析
①在线Layui示例寻找合适的选项卡
下面是静态效果展示:
②点击左侧右侧没有url属性
由于我们的工具类TreeVo不可能有我们数据库的全部字段,那么应该怎么动态生成拥有属性url的TreeVo工具类??
TreeVo工具类
package com.zking.util; import java.util.ArrayList; import java.util.List; import java.util.Map; public class TreeVo<T> { /** * 节点ID */ private String id; /** * 显示节点文本 */ private String text; /** * 节点状态,open closed */ private Map<String, Object> state; /** * 节点是否被选中 true false */ private boolean checked = false; /** * 节点属性 */ private Map<String, Object> attributes; /** * 节点的子节点 */ private List<TreeVo<T>> children = new ArrayList<TreeVo<T>>(); /** * 父ID */ private String parentId; /** * 是否有父节点 */ private boolean hasParent = false; /** * 是否有子节点 */ private boolean hasChildren = false; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getText() { return text; } public void setText(String text) { this.text = text; } public Map<String, Object> getState() { return state; } public void setState(Map<String, Object> state) { this.state = state; } public boolean isChecked() { return checked; } public void setChecked(boolean checked) { this.checked = checked; } public Map<String, Object> getAttributes() { return attributes; } public void setAttributes(Map<String, Object> attributes) { this.attributes = attributes; } public List<TreeVo<T>> getChildren() { return children; } public void setChildren(List<TreeVo<T>> children) { this.children = children; } public boolean isHasParent() { return hasParent; } public void setHasParent(boolean isParent) { this.hasParent = isParent; } public boolean isHasChildren() { return hasChildren; } public void setChildren(boolean isChildren) { this.hasChildren = isChildren; } public String getParentId() { return parentId; } public void setParentId(String parentId) { this.parentId = parentId; } public TreeVo(String id, String text, Map<String, Object> state, boolean checked, Map<String, Object> attributes, List<TreeVo<T>> children, boolean isParent, boolean isChildren, String parentID) { super(); this.id = id; this.text = text; this.state = state; this.checked = checked; this.attributes = attributes; this.children = children; this.hasParent = isParent; this.hasChildren = isChildren; this.parentId = parentID; } public TreeVo() { super(); } }
看完以上代码我们可以发现虽然没有我们想要的属性但是拥有private Map<String, Object> attributes属性,那么我们就可以在进行将平级数据转换成父子级数据的时候将遍历的平级数据直接加到Map集合中,这样该属性就拥有了数据库表的全部字段。
③点击左侧列表右侧内容多开问题
我们只需要在添加tab选项卡之前加一个判断即可,我们发现tab中的li标签上都有一个lay-id属性,我们只需将我们TreeVo的id赋给它,然后每次点击的时候通过jquery获取该标签,如果没有找到说明没有打开,如果找到了那么我们就选中它。
//点击左侧列表右侧选项卡打开 function opedTab(title, content, id) { //判断是否已经打开 var node=$('li[lay-id="'+id+'"]'); //没有找到该标签时就打开 if(node.length==0){ //因为element没有获取到要扩大权限(layui.use里有element) element.tabAdd('demo', { title : title, content :"<iframe frameborder='0' src='"+content+"' scrolling='auto' style='width:100%;height:100%;'></iframe>", id : id }) } //有该标签就打开 element.tabChange('demo', id) }
④优化公共文件
因为我们在页面上需要写大量的${pageContext.request.contextPath}非常的繁琐,所以我们就可以使用一个标签——base标签
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html "> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title></title> <!-- 引入layui.css--> <link rel="stylesheet" href="${pageContext.request.contextPath}/static/js/layui/css/layui.css"> <!-- 引入layui.js--> <script type="text/javascript" src="${pageContext.request.contextPath}/static/js/layui/layui.js"></script> <!-- base标签 --> <base href="${pageContext.request.contextPath}/"> </head> </html>
小贴士:
<base>
标签是HTML中的一个元标签(meta tag),用于指定页面中所有相对路径的基准URL。使用
<base>
标签可以改变页面中所有相对链接的基准URL,它是一种全局的设置。通常情况下,相对路径是以当前页面的URL为基准进行解析。但是,当使用<base>
标签时,相对路径将以<base>
标签中指定的URL为准。需要注意的是,一个页面只能有一个<base>
标签,并且应放置在<head>
标签中的最顶部。
2.Dao层的优化
package com.xw.dao; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.fasterxml.jackson.databind.ObjectMapper; import com.xw.entity.Permission; import com.zking.util.BaseDao; import com.zking.util.BuildTree; import com.zking.util.TreeVo; /**管理系统左侧列表 * @author 索隆 * */ public class PermissionDao extends BaseDao<Permission>{ /**获取管理的所有信息(平级数据) * @return * @throws Exception */ public List<Permission> list() throws Exception{ String sql="select * from t_oa_permission"; return super.executeQuery(sql, Permission.class, null); } /**将平级数据变成我们需要的父子级数据 * @return * @throws Exception */ public List<TreeVo<Permission>> menu() throws Exception{ //存放父子级的容器 List<TreeVo<Permission>> menu=new ArrayList<TreeVo<Permission>>(); //拿到平级数据 List<Permission> list = this.list(); //遍历平级数据 for (Permission permission : list) { //工具类帮助我们完成父子级关系 TreeVo<Permission> vo=new TreeVo<Permission>(); vo.setId(permission.getId()+"");//id vo.setParentId(permission.getPid()+"");//父级id vo.setText(permission.getName());//列表名称 //优化代码 //利用一个map集合保存TreeVo没有的属性 Map<String, Object> map=new HashMap<>(); //将数据的所有信息保存到map容器中 map.put("self", permission); vo.setAttributes(map); menu.add(vo); } //通过工具类筛选父级菜单的儿子,String是父级菜单的pid return BuildTree.buildList(menu, "-1"); } }
刚刚需求分析的时候也提到了,这里就不过多讲解,大家直接看代码即可。
3.JSP页面搭建
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE> <html> <head> <%@ include file="common/static.jsp"%> <script type="text/javascript" src="js/index.js"></script> </head> <body> <div class="layui-layout layui-layout-admin"> <div class="layui-header"> <div class="layui-logo layui-hide-xs layui-bg-black">OA会议系统</div> <!-- 头部区域(可配合layui 已有的水平导航) --> <!-- <ul class="layui-nav layui-layout-left"> 移动端显示 <li class="layui-nav-item layui-show-xs-inline-block layui-hide-sm" lay-header-event="menuLeft"><i class="layui-icon layui-icon-spread-left"></i></li> Top导航栏 <li class="layui-nav-item layui-hide-xs"><a href="">nav 1</a></li> <li class="layui-nav-item layui-hide-xs"><a href="">nav 2</a></li> <li class="layui-nav-item layui-hide-xs"><a href="">nav 3</a></li> <li class="layui-nav-item"><a href="javascript:;">nav groups</a> <dl class="layui-nav-child"> <dd> <a href="">menu 11</a> </dd> <dd> <a href="">menu 22</a> </dd> <dd> <a href="">menu 33</a> </dd> </dl></li> </ul> --> <!-- 个人头像及账号操作 --> <ul class="layui-nav layui-layout-right"> <li class="layui-nav-item layui-hide layui-show-md-inline-block"> <a href="javascript:;"> <img src="${pageContext.request.contextPath }/static/images/user/小黑子索隆.jpg" class="layui-nav-img">我的 </a> <dl class="layui-nav-child"> <dd> <a href="">修改信息</a> </dd> <dd> <a href="">安全管理</a> </dd> <dd> <a href="login.jsp">退出登录</a> </dd> </dl> </li> <li class="layui-nav-item" lay-header-event="menuRight" lay-unselect> <a href="javascript:;"> <i class="layui-icon layui-icon-more-vertical"></i> </a> </li> </ul> </div> <div class="layui-side layui-bg-black"> <div class="layui-side-scroll"> <!-- 左侧导航区域(可配合layui已有的垂直导航) --> <ul id="menu" class="layui-nav layui-nav-tree" lay-filter="menu"> </ul> </div> </div> <div class="layui-body"> <!-- 内容主体区域 --> <div class="layui-tab" lay-filter="demo" lay-allowclose="true"> <ul class="layui-tab-title"> </ul> <div class="layui-tab-content"> </div> </div> </div> <div class="layui-footer"> <!-- 底部固定区域 --> 底部固定区域 </div> </div> <script> var element,layer,util,$; layui.use(['element', 'layer', 'util','jquery'], function(){ element = layui.element ,layer = layui.layer ,util = layui.util ,$ = layui.jquery; $.ajax({ url: " Permission.action?methodName=listmenu", type: 'post', dataType: 'json', success: function(data) { //定义一个变量将回显的数据进行拼接,最终追加到指定标签上 var str=''; $.each(data,function(i,n){ str+='<li class="layui-nav-item layui-nav-itemed">'; str+=' <a class="" href="javascript:;">'+n.text+'</a>'; //判断有无children节点有就遍历 if(n.hasChildren){ //有children节点拿到children节点 var children=n.children; str+='<dl class="layui-nav-child">'; $.each(children,function(idx,node){ str+='<dd><a href="javascript:;" onclick="opedTab(\''+node.text+'\',\''+node.attributes.self.url+'\',\''+node.id+'\')">'+node.text+'</a></dd>'; }) str+='</dl>'; } str+='</li>'; }) //将拼接内容追加到指定ul标签 $("#menu").html(str); //渲染ul标签 element.render('menu'); } }) }); //点击左侧列表右侧选项卡打开 function opedTab(title, content, id) { //判断是否已经打开 var node=$('li[lay-id="'+id+'"]'); //没有找到该标签时就打开 if(node.length==0){ //因为element没有获取到所有要去上面扩大权限 element.tabAdd('demo', { title : title, content :"<iframe frameborder='0' src='"+content+"' scrolling='auto' style='width:100%;height:100%;'></iframe>", id : id }) } //有该标签就打开 element.tabChange('demo', id) } </script> </body> </html>
4.案例演示
登录成功才可访问我们的主页面
因为这里的url页面我项目中还没有编写,所以404是必然的,不用管他!!!
5.总结
- ①因为我们自己所编写的方法中要用到element,而这个元素我们在方法内没有获取所有要在layui.use(加载模块)获取element的时候扩大作用域。
- ②url在TreeVo工具类中没有该属性,所以我们要在平级数据转成父子级数据的时候下文章,加到Map中再将Map赋值给TreeVo中的Attributes属性,从而拿到数据库表的全部字段及内容。
- ③选项卡打开后不可重复打开,应该做判断。如果已经有该选项卡存在,那么我就让其选中,不存在我才打开。
到这里我的分享就结束了,欢迎到评论区探讨交流!!
如果觉得有用的话还请点个赞吧 ♥ ♥