[TOC] ## Angularjs [百度百科](https://baike.baidu.com/item/AngularJS/7140293?fr=aladdin "百度吧") ## inspina bootstrap比较好的后台管理模板,本身就支持了Angularjs版本,jumpserver就是使用的inspina的jquery版本 ## 登录界面 ![](https://box.kancloud.cn/b1602d9a6deb432a2aab0c07d567e128_1680x1050.png) ### 登录界面代码 ```html <div class="middle-box text-center loginscreen animated fadeInDown"> <div> <div> <h1 class="logo-name">SO</h1> </div> <h3>欢迎使用SmartOps</h3> {{ errorMessage }} <form class="m-t" ng-submit="login()"> <div class="form-group"> <input type="email" value="mail@shuaibo.wang" class="form-control" ng-model="loginForm.email" placeholder="登录邮箱" required=""> </div> <div class="form-group"> <input type="password" value="123456" class="form-control" placeholder="密码" ng-model="loginForm.password" required=""> </div> <button type="submit" class="btn btn-primary block full-width m-b">Login</button> <a ui-sref="forgot_password"><small>忘记密码?</small></a> <p class="text-muted text-center"><small>没有账号?</small></p> <a class="btn btn-sm btn-white btn-block" ui-sref="register">创建账号</a> </form> <p class="m-t"> <small>SmartOps &copy; 2018</small> </p> </div> </div> ``` ### 关于Angularjs的一些解答 ng-submit: 可以理解为交给那个函数去处理 ng-model: 可以理解为函数需要的参数 这里使用了login函数 ```js function LoginCtrl($scope, $location, AuthService) { $scope.login = function () { AuthService.login($scope.loginForm.email, $scope.loginForm.password ).then(function () { $location.path('/') } ).catch(function (reason) { $scope.errorMessage = reason; }) } } ``` #### 认证服务 这里面有利用到了一个AuthService,这个可以理解成为一个认证服务,用来检测用户是否登录没有登录就跳转到登录界面让用户去登录,由于采用了JSONRPC这种开发模式,后端就不会控制前端去跳转,所以只能靠前端代码判断是否登录了 ``` angular.module('inspinia').factory('AuthService', ['$q', '$timeout', 'jsonrpc', function ($q, $timeout, jsonrpc) { // 定义判断用户是否在线和token的变量 var user = null; var token = null; var next = 'index.main'; // return available functions for use in controllers return ({ isLoggedIn: isLoggedIn, login: login, logout: logout, register: register, getUserStatus: getUserStatus }); function isLoggedIn() { if (user) { return true; } else { return false; } } function login(email, password) { var deferred = $q.defer(); jsonrpc.request('user.verify', { username: email, password: password }) .then(function (result) { if (result.status == 0) { // 如果用户登录成功,记录其token,并将其设置成在线 token = result.token; user = true; deferred.resolve(); } else { user = false deferred.reject(); } }) .catch(function (error) { user = false; deferred.reject(); }) return deferred.promise; } function logout() { return } function register(email, password) { return } // 这里写了一个用户状态的接口,这个接口需要token认证,认证通过了就判断当前用户可以请求资源 function getUserStatus() { return jsonrpc.request('user.status', {token: token}).then(function (result) { if (result.status == 0) { user = true } else { user = false } }).catch(function (reason) { user=false }) } }]); ``` ### 禁止没登录去访问页面 angularjs访问每个页面会触发事件。这个需要在config.js去配置,比如访问这个页面需不需要认证,认证不通过然后控制其跳转 ```js angular .module('inspinia') .config(config) .run(function ($rootScope, $state, AuthService) { $rootScope.$state = $state $rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) { // 获取用户状态 AuthService.getUserStatus().then(function () { // 判断这个页面是不是需要登录,需要登录就判断当前有没有登录,没有登录就跳转到登录界面 if (toState.access.restricted && !AuthService.isLoggedIn()) { // 如果是从别的页面跳转过来的记录一下跳转之前的url,登录成功之后还跳转到之前的页面 AuthService.next=toState.name $state.go('login') } }) }) }) ``` ### angularjs自己的路由 angularjs拥有自己的路由功能通常的url是这样的 ``` index.html?#/模块名 ``` 这个需要在config里面定义 ```js function config($stateProvider, $urlRouterProvider, $ocLazyLoadProvider) { $urlRouterProvider.otherwise("/index/main"); $ocLazyLoadProvider.config({ // Set to true if you want to see what and when is dynamically loaded debug: true }); $stateProvider .state('index', { abstract: true, url: "/index", templateUrl: "static/views/common/content.html", }) .state('index.main', { url: "/main", templateUrl: "static/views/main.html", data: {pageTitle: 'Example view'}, access: {restricted: true} }) .state('index.minor', { url: "/minor", templateUrl: "static/views/minor.html", data: {pageTitle: 'Example view'}, access: {restricted: true} //这个就是判断需不需要登录 }) .state('login', { url: '/login', access: {restricted: false}, //登录界面就不要登录 templateUrl: "static/views/login.html", controller: 'LoginCtrl', } ) } ``` ### angularjs自己的控制器 Angularjs还有一个概念那就是controller,我js有100个函数,但是这个页面就需要1个,或者两个页面有相同的函数名但是功能不一样,这样做出来的项目很复杂,也容易混淆,协同起来也是有难度,这个控制器可以理解成一个个箱子把东西隔开了。 ```js .state('login', { url: '/login', access: {restricted: false}, //登录界面就不要登录 templateUrl: "static/views/login.html", controller: 'LoginCtrl', } ) ``` 这里就是login使用longinCtrl loginCtl里面包含了登录界面需要使用的login函数 ``` function LoginCtrl($scope, $state, AuthService) { $scope.login = function () { AuthService.login($scope.loginForm.email, $scope.loginForm.password ).then(function () { $state.go(AuthService.next) } ).catch(function (reason) { $scope.errorMessage = reason; }) } } ``` ### 怎么加载到Angular里面 ``` angular .module('inspinia') .config(function (jsonrpcConfigProvider) { jsonrpcConfigProvider.set({ url: '/api', returnHttpPromise: false }); }) .controller('MainCtrl', MainCtrl) .controller('LoginCtrl', ['$scope', '$location', 'AuthService', LoginCtrl]) ``` 这样一个登录的界面就做好了,别的页面也差不多就这些概念 ### Angularjs的插件 上面其实用到了一个插件[angular-jsonrpc-client](https://github.com/joostvunderink/angular-jsonrpc-client "angular-jsonrpc-client") Angular的插件注册需要在引用js的最上面 index.html ```html <!-- Main Angular scripts--> <script src="static/js/angular/angular.min.js"></script> <script src="static/js/plugins/oclazyload/dist/ocLazyLoad.min.js"></script> <script src="static/js/ui-router/angular-ui-router.min.js"></script> <script src="static/js/plugins/angular-jsonrpc-client.js"></script> <script src="static/js/bootstrap/ui-bootstrap-tpls-1.1.2.min.js"></script> <!-- Anglar App Script --> <script src="static/js/app.js"></script> ``` app.js ``` (function () { angular.module('inspinia', [ 'ui.router', // Routing 'oc.lazyLoad', // ocLazyLoad 'ui.bootstrap', // Ui Bootstrap 'angular-jsonrpc-client' ]) })(); ``` ## 登录身份的有效期 之前实现的有点小瑕疵,就是按F5刷新之后自动跳到登录界面,原因是因为service的token随着页面的刷新就被重置了。这里就需要做一些改动了,就是登录成功之后不仅要把token重新赋值,还写到cookie里面,然后刷新页面token从cookie里取出来,而不是null导致重新登录。需要改动的是services.js 这里需要用到了ngCookies自行app.js里面添加 services.js ```js angular.module('inspinia').factory('AuthService', ['$q', '$timeout', 'jsonrpc', '$cookies', function ($q, $timeout, jsonrpc, $cookies) { .... // 刷新界面从cookie里面读取回来 var token = $cookies.get('token'); ..... function login(email, password) { // create a new instance of deferred var deferred = $q.defer(); // send a post request to the server jsonrpc.request('user.verify', { username: email, password: password }) .then(function (result) { if (result.status == 0) { var expireDate = new Date(); expireDate.setDate(expireDate.getDate() + 1); token = result.token; // 登录成功后设置token到cookie $cookies.put("token",token,{'expires': expireDate}); user = true; deferred.resolve(); } else { user = false deferred.reject(); } }) .catch(function (error) { user = false; deferred.reject(); }) // return promise object return deferred.promise; } ........ }]); ``` ## 注销功能 注销功能相对是比较简单的,只需要将cookie里的token删除或者设置为空就可以 ```js function logout() { // create a new instance of deferred var deferred = $q.defer(); $cookies.remove('token') // return promise object return deferred.promise; } ```