1.基本功能 1.基本功能
1.1.常用页面隐藏处理 1.1.常用页面隐藏处理
对于使用频率较高且加载速率较慢的页面,可以采用页面隐藏处理。当该页面执行关闭操作后,并未真正关闭,而是采取隐藏操作。这一做法可以使得再次打开本页面时,渲染速度有明显提升。
2.配置方法 2.配置方法
2.1.常用页面隐藏处理 2.1.常用页面隐藏处理
1.index.html:使用ng-class指令,给 tab标签动态绑定一个隐藏的样式。
<!--页签-->
<div class="tab">
<ul>
<li ng-class="{'on':'todoListId'==activeTabId}" ng-dblclick="toggle()"> <a href="javascript:void(0)" ng-click="showTab('todoListId');"> <span class="show-pan">待办列表</span> </a> </li>
<li ng-class="{'on':resource.sysResourceId==activeTabId, 'closed-hide:resourcee.closed}" ng-dblclick="toggle()" ng-repeat="resource in tabArray | orderBy:'tabSeq' | filter : resFilter"> <a href="javascript:void(0)" ng-click="showTab(resource.sysResourceId)"> <span class="show-pan">{{resource.urlTitle}}</span> </a> <a href="javascript:void(0)" ng-click="closeTab(resource)">
<div class="tab-close close_on"></div> </a> </li>
</ul>
</div>
2.IndexModule.js:
1)添加 $scope.commonPages 数组,将需要采用隐藏方式处理的html页面一一加入,并给出对应的页面判断方法。
$scope.commonPages = []; // 常用页面列表,关闭作隐藏处理
$scope.maxCommonPagesCount = 5; // 关闭隐藏页面最大限制,超出数量时,关闭第一个页面
$scope.matchCommonPage = function(resource) {
var url = resource.url;
var matchPage = _.find($scope.commonPages,
function(commonPage) {
return url.indexOf(commonPage) >= 0;
});
// ## 下面这个奇怪的东西去掉
//$http.post($config.ctx + '/index.html').success(function (data) {
// $scope.userNameCn = data.msg;
//});
return matchPage;
};
2)修改 $scope.addTabByMenu 方法,对符合隐藏处理条件的页面特殊处理,并触发页面的 resetPage 事件。
/**
* 从菜单点击,新增tab页
* 菜单URL,没带$config.ctx
*/
$scope.addTabByMenu = function(resource) {
var matchPage = $scope.matchCommonPage(resource);
if (resource.urlType == 'GROUP') return;
var existNum = 0;
for (var j = 0; j < $scope.commonPages.length; j++) {
for (var i = 0; i < $scope.tabArray.length; i++) {
if ($scope.tabArray[i].url.indexOf($scope.commonPages[j]) > 0 && $scope.tabArray[i].closed) {
existNum++;
break;
}
}
}
if ($scope.tabArray && $scope.tabArray.length >= tabNum) {
GillionMsg.alert("提示", "打开的页签个数超过限制,请关闭掉没用的页签,再打开新的页签。");
return;
}
if (matchPage) {
var matchSource = $scope.matchCommonResource(matchPage, id);
$scope.lastOpenCommonPage(matchPage);
if (matchSource) {
var iframe = $('#' + matchSource.sysResourceId + '_frame')[0];
var closed = matchSource.closed;
var iframeScope;
if (iframe) {
iframeScope = iframe.contentWindow.$('body').scope();
}
matchSource.closed = false;
matchSource.tabSeq = $scope.tabSeq++;
if (matchSource.isPreload) {
delete matchSource.isPreload;
matchSource.urlTitle = resource.urlTitle;
matchSource.sysResourceId = resource.sysResourceId;
}
$scope.activeTabId = matchSource.sysResourceId;
if (iframeScope) {
if (!closed) {
iframeScope.$emit('closePage');
}
iframeScope.$emit('resetPage', resource);
}
} else {
resource.tabSeq = $scope.tabSeq++;
$scope.tabArray.push(resource);
}
return;
}
3)修改 $scope.addTab 方法,对符合隐藏处理条件的页面特殊处理,并触发页面的 resetPage 事件。
/**
* 从js 上调用,新增tab页
* URL,必须带$config.ctx
*/
$scope.addTab = function(resource) {
var tabScope;
var matchPage = $scope.matchCommonPage(resource);
var existNum = 0;
for (var j = 0; j < $scope.commonPages.length; j++) {
for (var i = 0; i < $scope.tabArray.length; i++) {
if ($scope.tabArray[i].url.indexOf($scope.commonPages[j]) > 0 && $scope.tabArray[i].closed) {
existNum++;
break;
}
}
}
try {
tabScope = document.getElementById(resource.sysResourceId + "_frame").contentWindow.angular.element("body").scope();
} catch(e) {
tabScope = null;
}
if ($scope.tabArray && $scope.tabArray.length >= tabNum) {
GillionMsg.alert("提示", "打开的页签个数超过限制,请关闭掉没用的页签,再打开新的页签。");
return;
}
if (matchPage) {
var matchSource = $scope.matchCommonResource(matchPage, id);
$scope.lastOpenCommonPage(matchPage);
if (matchSource) {
var iframe = $('#' + matchSource.sysResourceId + '_frame')[0];
var closed = matchSource.closed;
var iframeScope;
if (iframe) {
iframeScope = iframe.contentWindow.$('body').scope();
}
matchSource.closed = false;
matchSource.tabSeq = $scope.tabSeq++;
if (matchSource.isPreload) {
delete matchSource.isPreload;
matchSource.urlTitle = resource.urlTitle;
matchSource.sysResourceId = resource.sysResourceId;
}
$scope.activeTabId = matchSource.sysResourceId;
if (iframeScope) {
if (!closed) {
iframeScope.$emit('closePage');
}
iframeScope.$emit('resetPage', resource);
}
} else {
resource.tabSeq = $scope.tabSeq++;
$scope.tabArray.push(resource);
}
return;
}
if (!containsTab(id)) { //create tab
resource.parentTabId = $scope.activeTabId;
$scope.activeTabId = id;
resource.tabSeq = $scope.tabSeq++;
$scope.tabArray.push(resource);
} else {
$scope.activeTabId = id;
if (!tabScope || !tabScope._pageState || !tabScope._pageState.isDataModified || !tabScope._pageState.isDataModified()) {
$scope.refreshTabIframe(resource.url);
}
}
4)修改 $scope.closeTab 方法,对符合条件的页面关闭时执行隐藏操作(设置closed属性为true)
$scope.closeTab = function(resource) {
var doCloseTab = function() {
var matchPage = $scope.matchCommonPage(resource);
var id = resource.sysResourceId;
var preTabResource;
if (matchPage) {
resource.closed = true;
var iframe = $('#' + resource.sysResourceId + '_frame')[0];
if (iframe) {
iframe.contentWindow.$('body').scope().$emit('closePage');
}
setActiveTabId();
} else {
for (var i = 0; i < $scope.tabArray.length; i++) {
if ($scope.tabArray[i].sysResourceId == id) {
if ($scope.activeTabId == id) {
if (i == 0) {
$scope.activeTabId = 'todoListId';
$scope.activeTabTopIndex = -1;
} else {
if (containsTab(resource.parentTabId)) { //create tab
$scope.activeTabId = resource.parentTabId;
} else {
$scope.activeTabId = $scope.tabArray[i - 1].sysResourceId;
}
$scope.activeTabTopIndex = $scope.tabArray[i - 1].activeTabTopIndex;
}
}
$scope.tabArray.splice(i, 1);
}
}
}
function setActiveTabId() {
if ($scope.activeTabId == id) {
preTabResource = _.chain($scope.tabArray).filter(function(r) {
return ! r.closed && r.tabSeq < resource.tabSeq;
}).sortBy(function(r) {
return r.tabSeq;
}).last().value();
if (preTabResource) {
$scope.activeTabId = preTabResource.sysResourceId || 'todoListId';
} else {
$scope.activeTabId = 'todoListId';
}
}
}
};
3.theme.css(该样式建议写在main.css中,这样可以减少用户的手工配置。可以通过云平台直接生成)
1)添加隐藏样式
.close-hide {
display: none;
}
4.对应页面 JS的调整,以testCaseNewHot305EditBsCtrl.js为例说明。
1)在testCaseNewHot305EditBsCtrl.js增加如下代码,监听 resetPage 事件,调用 $scope.resetPage 方法
$scope.$on('resetPage',
function(event, data) {
if (isPreloadPage) {
$scope.onClosePage && $scope.onClosePage();
isPreloadPage = false;
}
$scope.resetPage(data.url);
});
function getQueryString(name, url) {
var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
if (!url) {
url = window.location.href;
};
var search = url.split('?')[1] || '';
search = search.split('#')[0] || '';
var r = search.match(reg);
if (r !== null) {
return decodeURI(r[2]);
}
return null;
};
2)在testCaseNewHot305EditBsCtrl.js增加如下代码。新增或修改$scope.resetPage 方法,方法根据传入 url 重设 Params 对应字段的参数值。页面内有懒加载Tab页的, 根据新的 url 重新添加 Tab 页。方法最后,调用 refresh 方法刷新页面数据。
$scope.resetPage = function(url) {
Params.testExam301Id = getQueryString('testExam301Id', url);
Params.baseViewId = getQueryString('baseViewId', url);
//预加载
var isPreloadPage = Params.isPreloadPage === 'true';
$scope.NewCell1467603413396Api.addTab({
title: '费用信息',
url: $scope.newCell1467603413396ApiNewCell1467603415646Url,
index: -1
},
false);
$scope.NewCell1467603413396Api.addTab({
title: '集装箱',
url: $scope.newCell1467603413396ApiNewCell1467603442668Url,
index: 0
},
false);
$scope.refreshDispPage();
}
$scope.$on('closePage',
function() {
$scope.onClosePage();
});
3)在testCaseNewHot305EditBsCtrl.js中,增加监听 closePage 事件,执行 $scope.onClosePage()方法。
$scope.$on('closePage',
function() {
$scope.onClosePage();
});
4)在testCaseNewHot305EditBsCtrl.js中,修改关闭懒加载Tab页的方法,在方法中重置tab页的 scope 引用。
$scope.onClosePage = function() {
//$scope.tabNode = {};
_.forEach($scope._bindedProps,
function(key) {
if (_.isArray($scope[key])) {
$scope[key] = [];
} else if (_.isObject($scope[key])) {
$scope[key] = {};
} else {
$scope[key] = null;
}
});
$scope._bindedProps = [];
var _lazyLoadingPages = ['费用信息', '集装箱', ];
var _noLazyLoadingPages = ['基本信息', ];
$scope.reset && $scope.reset();
if ($scope.testCaseNewHot305DataSource) {
$scope.testCaseNewHot305DataSource.records = [];
$scope.testCaseNewHot305DataSource.totalPage = undefined;
$scope.testCaseNewHot305DataSource.totalRecord = undefined;
$scope.$broadcast('TestCaseNewHot305Source', $scope.testCaseNewHot305DataSource);
}
// ## 选择第一个tab
var tabTemp = _noLazyLoadingPages[0] + "_undefined";
$scope.F0020Api.selectTab(tabTemp);
// ## 只关闭关闭iframe懒加载的tab (有iframe懒加载Tab页的情况)
// $scope.F0020Api.closeTab('货物_' + $scope.f0020ApiF00201Url);
// ## 清除所有 form 的校验
$scope.resetAndDisableAllFormValidator();
}
5)添加 $scope.bindTabProp() 方法,用于绑定值到 $scope 上,使用此方法绑定的属性会在关闭页面时会清空
/** 绑定$scope 属性方法,在页面关闭后,使用此方法绑定的属性会被清空 */
$scope.bindTabProp = function(key, val) {
$scope._bindedProps = $scope._bindedProps || [];
$scope[key] = val;
if ($scope._bindedProps.indexOf(key) < 0) {
$scope._bindedProps.push(key);
}
};
6)在testCaseNewHot305EditBsCtrl.js中,原来使用 GillionTabService.invoke 方法获取 tab 页 scope 的地方,改为使用 tab 控件的 getTabIframeScope(url) 方法。
/**
* GLPaaS生成
* 初始化懒加载页签scope作用域
*/
$scope.initPageTabScope = function(oneToOne) {
$scope.bindTabProp('newCell1467603413396ApiNewCell1467603415646Scope', $scope.NewCell1467603413396Api.getTabIframeScope($scope.newCell1467603413396ApiNewCell1467603415646Url) || {});
$scope.bindTabProp('newCell1467603413396ApiNewCell1467603442668Scope', $scope.NewCell1467603413396Api.getTabIframeScope($scope.newCell1467603413396ApiNewCell1467603442668Url) || {});
};
5.懒加载Tab页的 JS,以testCaseNewHot305ArFreightTabsRefEditBsCtrl.js为例说明。
1)在testCaseNewHot305ArFreightTabsRefEditBsCtrl.js中,有调用主页面 scope 执行监听的,需要在 $destroy 事件(移除Tab页时触发)时,解除这些监听。具体参考如下,新增testCaseNewHot305ScopeWatcher变量与testCaseNewHot305ScopeWatchers集合,前者用于存放监听的对象,后者用于存放前者。针对对应的Tab页面,当关闭时,将testCaseNewHot305ScopeWatchers中存放的监听统一解除。
var testCaseNewHot305ScopeWatcher;
var testCaseNewHot305ScopeWatchers = [];
testCaseNewHot305ScopeWatcher = $scope.$watchCollection('testCaseNewHot305Details',
function() {
if ($scope.testCaseNewHot305DetailDataSource) {
$scope.testCaseNewHot305DetailDataSource.records = $scope.testCaseNewHot305Details;
$scope.testCaseNewHot305DetailDataSource.totalRecord = $scope.testCaseNewHot305DetailDataSource.records.length;
if (!$scope.testCaseNewHot305DetailDataSource.totalPage) $scope.testCaseNewHot305DetailDataSource.totalPage = 1;
var checkRowTempIndex = [];
if ($scope.testCaseNewHot305DetailGrid.scope.checkedRows && $scope.testCaseNewHot305DetailGrid.scope.checkedRows.length > 0) {
angular.forEach($scope.testCaseNewHot305DetailGrid.scope.checkedRows,
function(row, index) {
var rowIndexTemp = _.findIndex($scope.testCaseNewHot305DetailDataSource.records, row);
checkRowTempIndex.push(rowIndexTemp);
});
}
$dataSourceManager.$rootScope.$broadcast("testCaseNewHot305DetailSource", $scope.testCaseNewHot305DetailDataSource);
if (checkRowTempIndex && checkRowTempIndex.length > 0) {
angular.forEach(checkRowTempIndex,
function(dataIndex, index) {
var row = $scope.testCaseNewHot305DetailDataSource.records[dataIndex];
var checked = Arrays.exists($scope.testCaseNewHot305DetailGrid.scope.checkedRows, row);
if (!checked) {
$scope.testCaseNewHot305DetailGrid.scope.checkedRows.push(row);
}
});
var checkRowIndex = [];
}
}
});
testCaseNewHot305ScopeWatchers.push(testCaseNewHot305ScopeWatcher);
$scope.$on('$destroy',
function() {
angular.forEach(testCaseNewHot305ScopeWatchers,
function(unWatch) {
unWatch();
});
testCaseNewHot305ScopeWatcher = null;
testCaseNewHot305ScopeWatchers = null;
});
2)在testCaseNewHot305ArFreightTabsRefEditBsCtrl.js中,需要绑定对象到主页面的 scope 时,不要直接赋值,改为调用主页面 $scope 的 bindTabProp() 方法,以便在关闭页面时将其重置释放内存。获取主页面 scope 可提取成方法方便调用。
具体方案如下,新增getXXXScope方法(XXX可以用主页面名称命名),方法中的写法可参考如下:
$scope.gettestCaseNewHot305Scope = function() {
var indexScope = top.angular.element("body").scope();
var frame = top.angular.element("#" + indexScope.activeTabId + "_frame");
var testCaseNewHot305Scope = frame[0].contentWindow.angular.element("body").scope();
return testCaseNewHot305Scope;
}
3)移除使用 GillionTabService.register() 方法注册 tab 页
/**
* GLPaaS生成
* 注册主页面可调用的方法
*/
// GillionTabService.register(function(active,param){//
// if(active && active==="$scope"){
// return $scope;
// } else {
// var obj = $scope[active];
// if(obj){
// if(angular.isFunction(obj)){
// var fn = $scope[active](param);
// return fn;
// }
// else return obj;
// }else {
// $scope.baseAlert("提示",active+"方法或者对象不存在!");
// return false;
// }
// }
// });
4)某些自定义方法存在内存内存泄露问题的,需要单独修改。
3.常用扩展 3.常用扩展