这是多年以前用传统JQuery(easyUi)做项目时遇到的问题,今天把解决思路发布出来,也许能帮助到还在使用老架构的同学。
在开发类ERP的后台管理系统时,经常会看到这样的布局结构
每打开一个菜单都是单独打开一个Tab页,easyUi打开Tab页有两种方式:
- 动态增加iframe
- 在同一个Dom树中增加div 的方式
同一Dom树中存在命名污染的问题,包括样式也会互相影响,新增加页面里的样式很可能影响原有页面的布局
因此我们采用iframe的方式实现:
function addTab(subtitle,url,icon,closable){
if(!$('#tabs').tabs('exists',subtitle)){
$('#tabs').tabs('add',{
title:subtitle,
content:createFrame(url),
closable:(closable==null?true:closable),
icon:icon,
fit:true
});
}else{
$.messager.confirm('提示',eship.messages.updateTab,function(r){
if (r){
$('#tabs').tabs('select',subtitle);
var currTab = $('#tabs').tabs('getSelected');
$('#tabs').tabs('update',{
tab:currTab,
options:{content:createFrame(url)}
});
}
});
}
tabClose();
}
function createFrame(url){
var s = '<iframe scrolling="auto" frameborder="0" src="'+url+'" style="width:100%;height:99%;"></iframe>';
return s;
}
我们在使用时iframe Tab页时,页面中经常会有打开对话框的需求。
因为我们采用了iframe的方式,其实打开对话框是在子页面的iframe的dom中打开的,因此会被主页面遮挡,如图所示:
对话框移动过程中会被Tab标签遮挡,并且无法继续向上移动,并且不同iframe传递参数也比较麻烦,不是很方便,因此决定进行封装,基本原理如下:
封装模态对话框插件
- 判断是否在最顶层dom中执行,如果不在获取到顶层dom对象
- 在最顶层iframe中自动增加一个div,并通过这个div打开模态对话框
- 用堆栈记录打开对话框的相关属性options
- 关闭时,依次调用堆栈中的对话框,并关闭
优点:
- 增加getDialogOption方法,可方便获取当前对话框的option对象,可以方便的通过该对象进行窗口之间的值传递。
- 在关闭时,增加回调方法,可以在关闭时方便的调用父窗体的回调方法。
/**
* jQuery dialog
*
* @author rogerkuo
*
* easy ui 对话框扩展,自动创建DIV,并将DIV放置在最顶层DOM中,避免对话框被iframe覆盖的情况
*/
(function($) {
$.joyplus = function(){};
$.joyplus.messager = function(){};
//私有方法,用来负责创建对话框
function _joy_show(options) {
var defaults = {
width : 800,
height : 500,
title : 'My Dialog',
modal : true,
onLoad : function(){
var topDiaOptions = $.joyplus.getDialogOption();
if( topDiaOptions.dialogId != undefined){//如果需要处理对话框连续弹出问题时,对焦点进行处理
var topBody = _joy_get_top_body();
var ele = $(topBody).find("#" + $.joyplus.getModelDialogId());
var inputs = $(ele).find("input");
if( inputs.length > 0 ){
inputs[0].focus();
}
}
}
//dialogId : ""用来判断是否同一窗体,避免同一个业务多次弹出一个对话框,造成对话框堆叠,如果没有,不作处理
};
var isString = (typeof options == "string");
if (isString) {
options = {};
}
var d = {};
$.extend(d , options);
var topDiaOptions = $.joyplus.getDialogOption();
if( topDiaOptions != undefined && topDiaOptions.dialogId != undefined && topDiaOptions.dialogId == d.dialogId ){
return;
}
var isDataFunction = false;
//新增dialog传值基础功能,可调用父窗体的方法,获取附加数据
if( jQuery.type(d.extdata) == "function"){
isDataFunction = true;
d.extdata = d.extdata.call(this);
}
//新增dialog传值grid功能
if( jQuery.type(d.grid) == "function"){
isDataFunction = true;
d.grid = d.grid.call(this);
}
if(!isDataFunction){
d = $.extend(d , options);
}
_joy_get_options_cache().push(d);
var opt = $.extend(defaults, options);
opt.onClose = $.joyplus.closeModelDialog;
var id = _joy_create_div();
var top = _joy_get_top_body();
var element = $(top).find("#" + id);
$(element).dialog(opt);
};
//获取最上层的dialog对象
function _joy_get_top_dialog() {
var stack = _joy_get_dialog_stack();
return stack.pop();
};
//获取对话框堆栈,因为用户可以在对话框上继续点开对话框,因次要记录对话框堆栈
//先进后出
function _joy_get_dialog_stack() {
var top = _joy_get_cahce();
return top;
};
//自动创建div,在dom的最顶层创建
function _joy_create_div() {
var new_id = _joy_get_new_id();
var stack = _joy_get_dialog_stack();
stack.push(new_id);
$(_joy_get_top_body()).last().append("<div id='" + new_id + "'></div>");
return new_id;
};
function _joy_get_top_body() {
var top = window.parent.document.body;
return $(top)
};
function _joy_get_cahce() {
var a = window.top.$.fn._cache;
return a;
};
function _joy_get_options_cache() {
return window.top.$.fn._options_cache;
};
function _joy_get_new_id() {
var date = new Date();
return date.getTime().toString();
};
$.joyplus.showModelDialog = function(options , ifr) {
if( ifr ){
_joy_show(options);
}
else{
//如果是最顶层的iframe
if (window.top == window) {
_joy_show(options);
} else {//如果不是最顶层的iframe,则执行最顶层的showModelDialog方法
options.curDom = window;
window.top.$.joyplus.showModelDialog(options);
}
}
};
//获取当前对话框的options
$.joyplus.getDialogOption = function(){
var options = _joy_get_options_cache();
return options[options.length-1];
};
//延时关闭
$.joyplus.delayedClose = function(millisecond){
var dialogId = $.joyplus.getModelDialogId();
if(dialogId){
$('#'+dialogId).dialog('minimize');
}
setTimeout($.joyplus.closeModelDialog,millisecond);
};
$.joyplus.closeModelDialog = function() {
if (window.top == window) {
var options = _joy_get_options_cache().pop();
//父窗体可以实现onClose方法,在对话框关闭时,会调用该方法
if (options.onClose != undefined && $.isFunction(options.onClose)) {
options.onClose();
}
//提供父窗体回调函数
if (options.callBack != undefined && $.isFunction(options.callBack)) {
options.callBack();
}
if (options.validObj != undefined) {
options.validObj.validatebox("validate");
}
//获取当前对话框id
var id = _joy_get_top_dialog();
var top = _joy_get_top_body();
//释放自动创建的div
var element = $(top).find("#" + id);
$(element).dialog("destroy");
} else {
window.top.$.joyplus.closeModelDialog();
}
};
$.joyplus.messager.alert = function(title, msg, icon, fn){
if( eship.messages[msg] != undefined ){
msg = eship.messages[msg];
}
$.messager.alert(title, msg, icon, fn);
};
//获取dialog对象ID
$.joyplus.getModelDialogId = function() {
var c = _joy_get_cahce();
return c[c.length - 1];
};
$.fn._cache = new Array();
$.fn._options_cache = new Array();
})(jQuery);
这样在使用时,只需调用简单方法即可
function invCageEdit(){
var row = $('#invCageDG').datagrid('getSelected');
if(row){
var options = {title:"出库包装",height:500,width:1000,contentOverflow:'hidden'};
options.invCageId = row.uuid;//需要传递的扩展属性
options.href = contextPath +'/web/comm/invCageItemDialog.jsp';
options.backFunc = function(data){
//updatePickItem();回调函数
};
$.joyplus.showModelDialog(options);
}else{
$.joyplus.messager.alert('提示',eship.messages.selectOne,'info');
}
}