AngularJs開發應用
主要介紹AngularJs的特性、應用骨架、應用剖析、與服務器的交互、及簡單的Demo
關於AngularJs
AngularJS是一款來自Google的前端JS框架。簡稱其爲 ng 。這款框架最核心特性有:MVC、模塊化、自動化雙向數據綁定、語義化標籤、依賴注入,等等。
AngularJS框架通過TDD(測試驅動)的方式開發的,從這個角度看,AngularJS是敏捷開發的一次成功實踐。
使用了指令的概念,AngularJS對DOM操作進行了徹底的封裝。
AngularJS框架是完全免費開源的。
關於 ng 的幾點:
- 對 IE 方面,它兼容 IE8 及以上的版本。
- 與 jQuery 集成工作,它的一些對象與 jQuery 相關對象表現是一致的。
- 使用 ng 時不要冒然去改變相關 DOM 的結構
HelloWorld
第一個Demo,HelloDynamic.html
<html ng-app>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
<script src="controllers.js"></script>
</head>
<body>
<div ng-controller='HelloController'>
<input ng-model='greeting.text'>
<p>{{greeting.text}}, World</p>
</div>
</body>
</html>
controllers.js
function HelloController($scope) {
$scope.greeting = { text: 'Hello' };
}
數據綁定
我們沒有在輸入框中註冊任何change事件監聽器就可以讓UI自動刷新,AngularJs會自動把輸入框和花括號中的文本更新爲所獲得值。
依賴注入
function HelloController($scope) {
$scope.greeting = { text: 'Hello' };
}
當然
這種神奇的效果是通過Angular的依賴注入機制實現的。
指令
我們在模板中看到一些新的屬性,這些屬性不屬於HTML規範。我們引進了花括號用來實現數據的綁定;引入了ng-controller用來指定每個控制器負責監視視圖的哪個部分;引入了ng-model,用來把輸入數據綁定到模型中的以部門屬性上。我們把這些叫做HTML擴展命令。
<html ng-app>
<head>
<title>Your Shopping Cart</title>
</head>
<body ng-controller='CartController'>
<h1>Your Shopping Cart</h1>
<div ng-repeat='item in items'>
<span>{{item.title}}</span>
<input ng-model='item.quantity'>
<span>{{item.price | currency}}</span>
<span>{{item.price * item.quantity | currency}}</span>
<button ng-click="remove($index)">Remove</button>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
<script>
function CartController($scope) {
$scope.items = [
{title: 'Paint pots', quantity: 8, price: 3.95},
{title: 'Polka dots', quantity: 17, price: 12.95},
{title: 'Pebbles', quantity: 5, price: 6.95}
];
$scope.remove = function(index) {
$scope.items.splice(index, 1);
};
}
</script>
</body>
</html>
<html ng-app>
ng-app 屬性用來告訴Angular頁面中的哪一個部分需要接受它的管理。放在html標籤中,說明它管理整個頁面。
<body ng-controller='CartController'>
使用一個叫做控制器的JavaScript類來管理頁面中的區域。在body標籤中引入一個控制器,就是在聲明CartController將會管理介於和之間的所有內容。
<div ng-repeat='item in items'>
ng-repeat的意思是,對於items數據中的每一個元素,都把
<span>{{item.title}}</span>
{{item.title}}將會獲取循環中當前item,然後把這個item的title屬性值插入到DOM中。
<input ng-model='item.quantity'>
定義ng-model將會在輸入框和item.quantity的值之間創建數據的綁定關係。
<span>{{item.price | currency}}</span>
單價或者總價都有美元的格式顯示。Angular帶有一種2叫做過濾器(filter)的特性,我們可以用它來轉換文本的格式,有一個內置過濾器叫做currency(貨幣),來顯示美元格式化。
<button ng-click="remove($index)">Remove</button>
這個按鈕可以讓用戶刪除購物車中的項目,$index代表過程中的循環計數,這樣就可以知道要刪除哪條記錄了。
<html ng-app='myApp'>
<body ng-controller='TextController'>
<p>{{someText.message}}</p>
<script
src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js">
</script>
<script>
var myAppModule = angular.module('myApp', []);
myAppModule.controller('TextController',
function($scope) {
var someText = {};
someText.message = 'You have started your journey.';
$scope.someText = someText;
});
</script>
</body>
</html>
我們把ng-app設置成模塊名稱myApp,然後調用Angular對象創建一個名爲myApp的模塊,並且把控制器函數傳遞給myApp模塊的controller函數。
流程
- 用戶請求應用起始頁
- 用戶的瀏覽器向服務器發起一次HTTP連接,然後加載index.html頁面,這個頁面裏面包含模板。
- Angular被加載到頁面中,等待頁面加載完成,然後查找ng-app指令,用來定義模板邊界。
- Angular遍歷模板,查找指令和綁定關係,這將啓動一些列的動作:註冊監聽器、執行一些DOM操作、從服務器獲取初始化數據。這項工作的結果是,應用將會啓動起來,並且模板被轉換成DOM視圖。
- 連接到服務器去加載需要展示給用戶的其他數據。
ng-change
數據變化觸發事件
<!doctype html>
<html ng-app>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
</head>
<body>
<form ng-controller="StartUpController">
Starting: <input ng-change="computeNeeded()"
ng-model="funding.startingEstimate">
Recommendation: {{funding.needed}}
</form>
<script>
function StartUpController($scope) {
$scope.funding = { startingEstimate: 0 };
$scope.computeNeeded = function() {
$scope.funding.needed = $scope.funding.startingEstimate * 10;
};
}
</script>
</body>
</html>
$watch
不管他是通過何種途徑進行刷新的,我們需要使用
<!doctype html>
<html ng-app>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
</head>
<body>
<form ng-controller="StartUpController">
Starting: <input ng-model="funding.startingEstimate">
Recommendation: {{funding.needed}}
</form>
<script>
function StartUpController($scope) {
$scope.funding = { startingEstimate: 0 };
computeNeeded = function() {
$scope.funding.needed = $scope.funding.startingEstimate * 10;
};
$scope.$watch('funding.startingEstimate', computeNeeded);
}
</script>
</body>
</html>
監控多個東西
$scope.$watch('things.a+things.b',callMe(...));
當然a和b也可以屬於不同的對象,只要需要,這個列表可以無限長。
需要監控things對象上的所有屬性,可以這樣做:
$scope.$watch('things',callMe(...),true);
true屬性是請求Angular遍歷things的屬性,當其中任何一個屬性發生變化時就會觸發callMe事件。
使用Moudle模塊組織依賴關係
<!doctype html>
<html lang='en' ng-app='ShoppingModule'>
<head>
<title>Shopping Cart</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
<link href="bootstrap.css" rel="stylesheet">
</head>
<body ng-controller="ShoppingController">
<h1>Shop!</h1>
<table>
<tr ng-repeat="item in items">
<td>{{item.title}}</td>
<td>{{item.description}}</td>
<td>{{item.price | currency}}</td>
</tr>
</table>
<script>
function ShoppingController($scope, Items) {
$scope.items = Items.query();
}
var shoppingModule = angular.module('ShoppingModule', []);
// Set up the service factory to create our Items interface to the
// server-side database
shoppingModule.factory('Items', function() {
var items = {};
items.query = function() {
// In real apps, we'd pull this data from the server...
return [
{title: 'Paint pots', description: 'Pots full of paint', price: 3.95},
{title: 'Polka dots', description: 'Dots with polka', price: 2.95},
{title: 'Pebbles', description: 'Just little rocks', price: 6.95}
];
};
return items;
});
</script>
</body>
</html>
利用模塊和模塊內置的依賴注入功能,我們可以把控制器寫的更加的簡單:
function ShoppingController($scope, Items) {//倆個參數是無序的
$scope.items = Items.query();
}
Items已定義爲一個服務,定義的方式有三種:
1. provider(name,Object OR constructor()),一個可配置的服務,創建的邏輯比較複雜。如果你傳遞了一個Object做爲參數,那麼這個Object必須帶有一個名爲
3. service(name,constructor()),一個不可配置的服務,創建邏輯比較簡單。與上面的provider函數的constructor參數類似,Angular調用它可以創建服務實例。
使用過濾器格式化數據
語法:{{expression | filterName:parameter1: …parameterN}}
表達式可以是任意的Angular表達式,filterName是你需要使用的過濾器的名稱,過濾器的多個參數之間用冒號分隔。
{{10.1 | currency}}對應$10.10
Angular內置的過濾器還有date , number ,uppercase
{{10.1 | currency | number : 0}}對應顯示$10
不必受限於內置的過來器,可以自定義過濾器,標題文字首字母大寫
<!doctype html>
<html lang='en' >
<head>
<title>TitleCaps</title>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
</head>
<body ng-app='HomeModule' ng-controller="HomeController">
<h1>{{pageHeading | titleCase}}</h1>
<script>
function HomeController($scope) {
$scope.pageHeading = 'behold the majesty of your page title';
}
var homeModule = angular.module('HomeModule', []);
homeModule.filter('titleCase', function() {
var titleCaseFilter = function(input) {
var words = input.split(' ');
for (var i = 0; i < words.length; i++) {
words[i] = words[i].charAt(0).toUpperCase() + words[i].slice(1);
}
return words.join(' ');
};
return titleCaseFilter;
});
</script>
</body>
</html>
使用路由和$location切換視圖
$routeProvider
index.html
<!doctype html>
<html ng-app="AMail">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
<script src='controllers.js'></script>
</head>
<body>
<h1>A-Mail</h1>
<div ng-view></div>
</body>
</html>
我們僅僅把標題放在裏面,然後在用ng-view指令來告訴Angular把視圖顯示在這兒。
list.html
<table>
<tr>
<td><strong>Sender</strong></td>
<td><strong>Subject</strong></td>
<td><strong>Date</strong></td>
</tr>
<tr ng-repeat='message in messages'>
<td>{{message.sender}}</td>
<td><a ng-href='#/view/{{message.id}}'>{{message.subject}}</a></td>
<td>{{message.date}}</td>
</tr>
</table>
由於所有視圖模板都會被插入到剛纔所創建的外殼中,所以可以把它們都編成HTML文檔片段。用ng-repeat指令來遍歷郵件列表,然後把它們渲染到table中。
我們想實現用戶點擊一個主題就能被導航到相應的郵件中。我們在URL和message.id之間進行了數據綁定,所以用戶點擊id=1的郵件就會被導航到/#/view/1。這種根據URL導航的方式叫做深度鏈接。
detail.html
<div><strong>Subject:</strong> {{message.subject}}</div>
<div><strong>Sender:</strong> {{message.sender}}</div>
<div><strong>Date:</strong> {{message.date}}</div>
<div>
<strong>To:</strong>
<span ng-repeat='recipient in message.recipients'>{{recipient}} </span>
</div>
<div>{{message.message}}</div>
<a href='#/'>Back to message list</a>
爲了把這些模板關聯到對應的控制器上,我們將會給
controllers.js
// Create a module for our core AMail services
var aMailServices = angular.module('AMail', []);
// Set up our mappings between URLs, templates, and controllers
function emailRouteConfig($routeProvider) {
$routeProvider.
when('/', {
controller: ListController,
templateUrl: 'list.html'
}).
// Notice that for the detail view, we specify a parameterized URL component
// by placing a colon in front of the id
when('/view/:id', {
controller: DetailController,
templateUrl: 'detail.html'
}).
otherwise({
redirectTo: '/'
});
}
// Set up our route so the AMail service can find it
aMailServices.config(emailRouteConfig);
// Some fake emails
messages = [{
id: 0, sender: '[email protected]', subject: 'Hi there, old friend',
date: 'Dec 7, 2013 12:32:00', recipients: ['[email protected]'],
message: 'Hey, we should get together for lunch sometime and catch up.'
+'There are many things we should collaborate on this year.'
}, {
id: 1, sender: '[email protected]',
subject: 'Where did you leave my laptop?',
date: 'Dec 7, 2013 8:15:12', recipients: ['[email protected]'],
message: 'I thought you were going to put it in my desk drawer.'
+'But it does not seem to be there.'
}, {
id: 2, sender: '[email protected]', subject: 'Lost python',
date: 'Dec 6, 2013 20:35:02', recipients: ['[email protected]'],
message: 'Nobody panic, but my pet python is missing from her cage.'
+'She doesn\'t move too fast, so just call me if you see her.'
} ];
// Publish our messages for the list template
function ListController($scope) {
$scope.messages = messages;
}
// Get the message id from the route (parsed from the URL) and use it to
// find the right message object.
function DetailController($scope, $routeParams) {
$scope.message = messages[$routeParams.id];
}
與服務器交互
Angular提供$http服務,使得與服務器的交互更加容易。待詳解。
<!doctype html>
<html lang='en' ng-app>
<head>
<title>Shopping Cart</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
</head>
<body ng-controller="ShoppingController">
<h1>Shop!</h1>
<table>
<tr ng-repeat="item in items">
<td>{{item.title}}</td>
<td>{{item.description}}</td>
<td>{{item.price | currency}}</td>
</tr>
</table>
<script>
function ShoppingController($scope, $http) {
$http.get('/products').success(function(data, status, headers, config) {
$scope.items = data;
});
}
</script>
</body>
</html>
使用指令修改DOM
<!doctype html>
<html lang='en' ng-app='app'>
<head>
<title>Get focused</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
</head>
<body ng-controller="SomeController">
<button ng-click="clickUnfocused()">
Not focused
</button>
<button ngbk-focus ng-click="clickFocused()">
I'm very focused!
</button>
<div>{{message.text}}</div>
<script>
function SomeController($scope) {
$scope.message = { text: 'nothing clicked yet' };
$scope.clickUnfocused = function() {
$scope.message.text = 'unfocused button clicked';
};
$scope.clickFocused = function() {
$scope.message.text = 'focus button clicked';
};
}
var appModule = angular.module('app', []);
appModule.directive('ngbkFocus', function() {
return {
link: function(scope, element, attrs, controller) {
element[0].focus();
}
};
});
</script>
</body>
</html>
你會看到焦點在第二個按鈕上面。
校驗用戶輸入
Angular爲表單添加了一些很好用的特性
<!doctype html>
<html lang='en' ng-app>
<head>
<title>Validate me!</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
<style type="text/css">
.ng-invalid {
border-color: red;
}
</style>
</head>
<body>
<h1>Sign Up</h1>
<form name='addUserForm' ng-controller="AddUserController">
<div ng-show='message'>{{message}}</div>
<div>First name: <input name='firstName' ng-model='user.first' required></div>
<div>Last name: <input ng-model='user.last' required></div>
<div>Email: <input type='email' ng-model='user.email' required></div>
<div>Age: <input type='number'
ng-model='user.age'
ng-maxlength='3'
ng-min='1'></div>
<div><button ng-click='addUser()'
ng-disabled='!addUserForm.$valid'>Submit</button></div>
</form>
<script>
function AddUserController($scope) {
$scope.message = '';
$scope.addUser = function () {
// TODO for the reader: actually save user to database...
$scope.message = 'Thanks, ' + $scope.user.first + ', we added you!';
};
}
</script>
</body>
</html>
我們可以通過$valid屬性獲取表單的校驗狀態。配合ng-disabled,表單沒有輸入完成時禁用submit按鈕。
SpringMVC AngularJs 交互
angularjs.jsp
<%--
Created by IntelliJ IDEA.
User: fanchengwei
Date: 2016/9/29
Time: 下午2:10
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html ng-app="myApp">
<!--
ng-app用來告訴Angular頁面中的哪部門需要接受它的管理
-->
<head lang="en">
<meta charset="utf-8">
<title>Teams List App</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.1.1/css/bootstrap.min.css">
<script src="http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.1.1/bootstrap.min.js"></script>
<script src="webpage/com/kd/business/angularjs/services.js"></script>
<script src="webpage/com/kd/business/angularjs/app.js"></script>
</head>
<body>
<div class="row-fluid">
<div class="span3" ng-controller="FilterCtrl">
<form class="form-horizontal">
<div class="controls-row">
<label for="searchTextBox" class="control-label">Search:</label>
<div class="controls">
<input type="text" id="searchTextBox" ng-model="filterService.searchText">
</div>
</div>
<div class="controls-row">
<label for="sportComboBox" class="control-label">Sport:</label>
<div class="controls">
<select id="sportComboBox" ng-model="filterService.activeFilters.sport">
<option ng-repeat="sport in ['Basketball', 'Hockey', 'Football']">{{sport}}</option>
</select>
</div>
</div>
<div class="controls-row">
<label for="cityComboBox" class="control-label">City:</label>
<div class="controls">
<select id="cityComboBox" ng-model="filterService.activeFilters.city">
<option ng-repeat="city in ['Dallas', 'Los Angeles', 'Boston', 'New York']">{{city}}</option>
</select>
</div>
</div>
<div class="controls-row">
<label class="control-label">Featured:</label>
<div class="controls">
<input type="checkbox" ng-model="filterService.activeFilters.featured" ng-false-value="" />
</div>
</div>
</form>
</div>
<div class="offset1 span8" ng-controller="ListCtrl">
<table border="1">
<thead>
<tr>
<th>key_p</th>
<th>position</th>
<th>responsible_person</th>
</tr>
</thead>
<tbody id="teamListTable">
<tr ng-repeat="team in teamsList | filter:filterService.activeFilters | filter:filterService.searchText">
<td>{{team.key_p}}</td>
<td>{{team.position}}</td>
<td>{{team.responsible_person}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>
app.js
var app = angular.module('myApp', ['myApp.services']);
app.controller('ListCtrl', function ($scope, $http, filterService) {
$scope.filterService = filterService;
var url = "angularJsController.do?query";
$http({method: 'GET', url: url}).success(function (list, status, headers, config) {
$scope.teamsList = list;
}).error(function (list, status, headers, config) {
console.log("error");
});
});
app.controller('FilterCtrl', function ($scope, filterService) {
$scope.filterService = filterService;
});
services.js
angular.module('myApp.services', []).
factory('filterService', function() {
return {
activeFilters: {},
searchText: ''
};
});
AngularJsController.java
package com.kd.business.angularjs;
import com.kd.business.smart_socket.service.ZzSmartsocketServiceI;
import com.kd.platform.web.system.service.SystemService;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;
/**
* AngularJsController
*
* @author Frey Fan
* @date 2016/9/29
* 測試類AngularJs
*/
@Scope("prototype")
@Controller
@RequestMapping("/angularJsController")
public class AngularJsController {
@Autowired
private ZzSmartsocketServiceI zzSmartsocketService;
@Autowired
private SystemService systemService;
@RequestMapping(params={"init"})
public ModelAndView init(HttpServletRequest request)
{
return new ModelAndView("com/kd/business/angularjs/angularjs");
}
@RequestMapping(params = {"query"})
public ResponseEntity<List<Map<String, Object>>> query(HttpServletRequest request, HttpServletResponse response){
List list = systemService.findForJdbc("select key_p ,position,responsible_person from zz_smartsocket",null);
return new ResponseEntity<List<Map<String, Object>>>(list, HttpStatus.OK);
}
}