页面隐藏

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.常用扩展

 

4.版本更新 4. 版本更新