前端框架Layui实现动态选项卡&iframe使用(附源码)

简介: 前端框架Layui实现动态选项卡&iframe使用(附源码)

一、前言

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属性,从而拿到数据库表的全部字段及内容。
  • ③选项卡打开后不可重复打开,应该做判断。如果已经有该选项卡存在,那么我就让其选中,不存在我才打开。

到这里我的分享就结束了,欢迎到评论区探讨交流!!

如果觉得有用的话还请点个赞吧 ♥  ♥


相关文章
|
4月前
|
编解码 前端开发 JavaScript
.NET_web前端框架_layui_栅格布局
【8月更文挑战第27天】
52 4
|
4月前
|
前端开发 JavaScript
用iframe的方式实现微前端
微前端是最近几年火起来的概念,iframe是早期实现微前端的理想方案,而现在有了其它的方案,比如qianduan框架,single-spa,以及webpack5带来的联邦模块方案。但是每一个方案都有其优缺点,感兴趣的可以去实践一下。
|
2月前
|
前端开发 程序员 API
前端|基于 Layui 实现动态搜索选择框
网页端实现动态搜索选择框,要求下拉选项列表能根据用户输入内容动态刷新,最终提交的值必须是由选项列表中点选的。
50 3
|
2月前
|
JSON 前端开发 Java
震惊!图文并茂——Java后端如何响应不同格式的数据给前端(带源码)
文章介绍了Java后端如何使用Spring Boot框架响应不同格式的数据给前端,包括返回静态页面、数据、HTML代码片段、JSON对象、设置状态码和响应的Header。
158 1
震惊!图文并茂——Java后端如何响应不同格式的数据给前端(带源码)
|
2月前
|
存储 前端开发 Java
验证码案例 —— Kaptcha 插件介绍 后端生成验证码,前端展示并进行session验证(带完整前后端源码)
本文介绍了使用Kaptcha插件在SpringBoot项目中实现验证码的生成和验证,包括后端生成验证码、前端展示以及通过session进行验证码校验的完整前后端代码和配置过程。
239 0
验证码案例 —— Kaptcha 插件介绍 后端生成验证码,前端展示并进行session验证(带完整前后端源码)
|
2月前
|
JSON 前端开发 数据格式
@RequestMapping运用举例(有源码) 前后端如何传递参数?后端如何接收前端传过来的参数,传递单个参数,多个参数,对象,数组/集合(有源码)
文章详细讲解了在SpringMVC中如何使用`@RequestMapping`进行路由映射,并介绍了前后端参数传递的多种方式,包括传递单个参数、多个参数、对象、数组、集合以及JSON数据,并且涵盖了参数重命名和从URL中获取参数的方法。
173 0
@RequestMapping运用举例(有源码) 前后端如何传递参数?后端如何接收前端传过来的参数,传递单个参数,多个参数,对象,数组/集合(有源码)
|
2月前
|
JSON 前端开发 JavaScript
Vue微前端新探:iframe优雅升级,扬长避短,重获新生
Vue微前端新探:iframe优雅升级,扬长避短,重获新生
130 0
|
2月前
|
JavaScript 前端开发
前端js,vue系统使用iframe嵌入第三方系统的父子系统的通信
前端js,vue系统使用iframe嵌入第三方系统的父子系统的通信
|
2月前
|
前端开发 JavaScript 小程序
前端uni开发后端用PHP的圈子系统该 如何做源码?
圈子系统系统基于TP6+Uni-app框架开发;客户移动端采用uni-app开发,管理后台TH6开发。系统支持微信公众号端、微信小程序端、H5端、PC端多端账号同步,可快速打包生成APP
|
4月前
|
前端开发 JavaScript 应用服务中间件
【uniapp】谷歌授权登录,前端uniapp直调(含源码)
本文介绍如何在uniapp项目中实现谷歌授权登录,无需后端参与。文章分为三部分:1)谷歌授权登录流程,详细说明从用户点击登录到获取用户信息的整个过程;2)谷歌开发者控制台配置,包括创建项目、配置同意屏幕及OAuth客户端ID等步骤;3)uniapp前端实操,提供具体代码示例,展示如何获取授权码并用其交换访问令牌,最终获取用户信息
177 2
【uniapp】谷歌授权登录,前端uniapp直调(含源码)