angularjs前端portal技术简介
portal 系统是一种主流的前端架构设计模式,在现代应用开发中被广泛采用。它通过灵活的模块组合和高度可定制化的功能特性,在满足个性化需求方面展现出显著优势。基于这些特点,在angularjs框架下我们深入探讨其前后端结合的技术实现方案。
缺乏对比则难以发现不足,在比较Google Igleence Portal与基于AngularJS构建的Portal时应关注哪些问题。
网址:http://www.igoogleportal.com/

如上图所示,经分析,igoogle portal具备如下特点:
1.多视图且视图的数目和大小全为用户自定义
2.视图中的内容为用户自定义,跳转为用户自定义
3.视图可自由拖拽视图内容可编辑
随后我们以探究传统AngularJS前端项目的生命周期及启动机制为基础展开探讨。(探究如何利用AngularJS构建高度可量身定制的portal)
1.angularjs的视图ui-view定义在ui-router中
2.ui-router定义在angularjs的config()中
配置项(Config)在其后是Run项(Run),随后是Controller(Controller)均会被先期执行。当在Controller中时,无法修改配置项(Config)的内容。
熟悉了我们目标的特性及其采用的技术。
随后我们将对这些问题进行一一解决。
基于igoogle portal具有的特性,在我们的portal中将执行以下任务:
1.项目启动时读取后台信息,取出用户定义视图及内容。
2.根据用户储存信息,动态设置ui-router与ui-view。
3.加入拖拽的控件控制用户可以对视图进行拖拽与编辑。
为实现与后端的数据交互,在项目启动时需要触发一个angular实例,并在其生命周期中的特定阶段(如初始化阶段)通过curl协议从后端获取数据(也可采用Ajax技术,在项目初始化时与后端进行数据交互)。
二、为户储信息的管理需求,在系统架构中按需配置UI Router与UI View组件。应在配置文件中预先定义Router代理,并在运行时阶段进行动态配置UI Router与UI View组件,并实现相应的监听功能以确保数据完整性。
通过angular-sortable-view空间实现视图的拖拽操作和编辑功能。angular-sortable-view的网址为https://github.com/kamilkp/angular-sortable-view ,由于较为简便的操作方式,在此不做详细说明。
废话不多说,经分析代码如下:
index.html 去除ng-app采用手动启动
<div ng-cloak>
<page-ribbon></page-ribbon>
<div ui-view="navbar" ng-cloak></div>
<div class="container">
<div class="well container" ui-view="content">
<!-- Angular views -->
</div>
</div>
</div>
在angular.module中引入angular-sortable-view依赖项,在启动angular.run的过程中加入initPortalHome方法
(function() {
'use strict';
angular
.module('jhipsterApp', [
'ngStorage',
'tmh.dynamicLocale',
'pascalprecht.translate',
'ngResource',
'ngCookies',
'ngAria',
'ngCacheBuster',
'ngFileUpload',
'ui.bootstrap',
'ui.bootstrap.datetimepicker',
'ui.router',
'infinite-scroll',
// jhipster-needle-angularjs-add-module JHipster will add new module here
'angular-loading-bar',
'angular-sortable-view',
])
.run(run)
run.$inject = ['stateHandler', 'translationHandler','$state','$urlRouter','$http'];
function run(stateHandler, translationHandler,$state,$urlRouter,$http) {
stateHandler.initialize();
translationHandler.initialize();
initPortalHome($http,$urlRouter);
}
手动启动angular
angular.element(document).ready(function() {
angular.bootstrap(document, ['jhipsterApp']);
});
})();
config方法中设置setStateProviderRef代理方法
(function() {
'use strict';
angular
.module('jhipsterApp')
.config(stateConfig);
stateConfig.$inject = ['$stateProvider','$urlRouterProvider'];
function stateConfig($stateProvider,$urlRouterProvider) {
setStateProviderRef($stateProvider,$urlRouterProvider);
$stateProvider.state('app', {
abstract: true,
views: {
'navbar@': {
templateUrl: 'app/layouts/navbar/navbar.html',
controller: 'NavbarController',
controllerAs: 'vm'
}
}
});
}
})();
最后是setStateProviderRef与initPortalHome方法中的代码:
var $stateProviderRef = null;
var $urlRouterProviderRef = null;
function setStateProviderRef($stateProvider,$urlRouterProvider){
$urlRouterProvider.deferIntercept();
$urlRouterProviderRef = $urlRouterProvider;
$stateProviderRef = $stateProvider;
}
function initPortalHome($http,$urlRouter,$state){
$http.get("state.info.json").success(function(data){
var viewInfo=data;
var viewListState = {
url: '/home',
parent: 'home',
data: {
authorities: []
},
views: {}
}
angular.forEach(viewInfo, function (view) {
viewListState.views[view.viewName] = {
templateProvider: function ($timeout) {
var html="<h1>"+view.template+"</h1>";
return html
},
controller: 'HomeController',
controllerAs: 'vm'
};
});
$stateProviderRef.state('home', {
parent: 'app',
abstract:true,
data: {
authorities: []
},
views: {
'content@': {
templateProvider: function ($timeout,$compile,$rootScope) {
var html='';
var i=1;
$rootScope.viewInfo=viewInfo;
$rootScope.onStart=function(item,part,index,helper){
//拖拽开始事件
}
$rootScope.onStop=function(item,part,index,helper){
//拖拽停止事件
}
$rootScope.onSort=function(item,partFrom,partTo,indexFrom,indexTo){
//排序事件
}
$rootScope.addViews=function(){
var viewName="Hello World"+i;
var newViewInfo={};
newViewInfo.class='col-md-2 pad-50 bd-sky';
newViewInfo.viewName=viewName;
newViewInfo.template='<div>'+viewName+'</div>';
$rootScope.viewInfo.push(newViewInfo);
i++;
};
$rootScope.removeViews=function(viewName){
for(var i=0;i< $rootScope.viewInfo.length;i++){
if($rootScope.viewInfo[i].viewName==viewName){
$rootScope.viewInfo.splice(i, 1);
break;
}
}
}
return $timeout(function () {
var html='<div><button ng-click="addViews()" class="btn btn-primary btn-lg glyphicon glyphicon-plus"></button></div>' +
'<div class="sortable-container" sv-root sv-part="viewInfo"' +
' sv-on-start="onStart($item, $part, $index, $helper)" ' +
' sv-on-stop="onStop($item, $part, $index, $helper)" ' +
'sv-on-sort="onSort($item, $partFrom, $partTo, $indexFrom, $indexTo)">' +
'<div ng-repeat="item in viewInfo" sv-element="opts" class="{{item.class}}">' +
'<span sv-handle>移动</span><span ng-click="removeViews(item.viewName)" class="glyphicon glyphicon-remove"></span>' +
'<div sv-helper>' +
'<span style="background:#ffe87c" class="{{item.class}}">{{item.viewName}}<span class="glyphicon glyphicon-minus"></span><span class="glyphicon glyphicon-refresh"></span><span class="glyphicon glyphicon-resize-full"></span><span class="glyphicon glyphicon-align-justify"></span></span>' +
'</div>' +
' <div ui-view="{{item.viewName}}"></div> ' +
'</div>' +
'</div>';
//for(var i=0;i<viewInfo.length;i++){
// html=html+'{{viewInfo.length}}<div ui-view='+viewInfo[i].viewName+'></div>';
//}bb
return html;
}, 100);
},
controller: 'HomeController',
controllerAs: 'vm'
}
}
}).state('home-test', viewListState);
$urlRouter.sync();
$urlRouter.listen();
$state.go('home');
});
}
效果如图所示:

