HTML非常適合于聲明靜態(tài)的文檔,但是當(dāng)我們?cè)噲D使用它在web應(yīng)用程序中聲明動(dòng)態(tài)視圖時(shí),它顯得力不從心。AngularJS能為您的應(yīng)用程序擴(kuò)展HTML的詞匯。由此產(chǎn)生的環(huán)境非常具有有表現(xiàn)力、可讀性強(qiáng)、快速發(fā)展。
其他處理HTML的缺點(diǎn)的框架要么是抽象出HTML、CSS、和/或JavaScript,要么為操縱DOM提供一個(gè)必要的方式。它們都不能解決一個(gè)根本問題,即HTML不是為動(dòng)態(tài)視圖設(shè)計(jì)的。
AngularJS是用來構(gòu)建框架的工具集,很適全于你的應(yīng)用程序開發(fā)。它完全可擴(kuò)展,而且與別的庫(kù)協(xié)作得很好。每個(gè)功能可以被修改或替代,以適合你的獨(dú)一無二的開發(fā)工作流以及功能需要。繼續(xù)閱讀以弄懂為何。
index.html
<!doctype html>
<html ng-app>
<head>
<script src="https://atts.w3cschool.cn/attachments/image/wk/angularjs/angular.min.js"></script>
</head>
<body>
<div>
<label>Name:</label>
<input type="text" ng-model="yourName" placeholder="Enter a name here">
<hr>
<h1>Hello {{yourName}}!</h1>
</div>
</body>
</html>
數(shù)據(jù)綁定是每當(dāng)模型改變時(shí)更新視圖的自動(dòng)方法,當(dāng)視圖改變時(shí),同樣也會(huì)更新模型。這非常棒,因?yàn)閺哪阈枰獡?dān)心的列表中它減去了DOM操縱。
控件是DOM元素后面的行為。AngularJS讓你能夠用一個(gè)干凈可讀的形式表達(dá)行為,不需要更新DOM的通常樣板、注冊(cè)回調(diào)或者觀察模型變化。
與別的框架不同,不需要為包裝訪問器方法中的模型,而繼承私有類型。Angular模型是扁平的舊式JavaScript對(duì)象。這使你的代碼容易讀取、容易維護(hù)、可重用,還不需要樣板。
index.html
<!doctype html>
<html ng-app="todoApp">
<head>
<script src="https://atts.w3cschool.cn/attachments/image/wk/angularjs/angular.min.js"></script>
<script src="todo.js"></script>
<link rel="stylesheet" href="todo.css">
</head>
<body>
<h2>Todo</h2>
<div ng-controller="TodoListController as todoList">
<span>{{todoList.remaining()}} of {{todoList.todos.length}} remaining</span>
[ <a href="" ng-click="todoList.archive()">archive</a> ]
<ul class="unstyled">
<li ng-repeat="todo in todoList.todos">
<input type="checkbox" ng-model="todo.done">
<span class="done-{{todo.done}}">{{todo.text}}</span>
</li>
</ul>
<form ng-submit="todoList.addTodo()">
<input type="text" ng-model="todoList.todoText" size="30"
placeholder="add new todo here">
<input class="btn-primary" type="submit" value="add">
</form>
</div>
</body>
</html>
todo.js
angular.module('todoApp', [])
.controller('TodoListController', function() {
var todoList = this;
todoList.todos = [
{text:'learn angular', done:true},
{text:'build an angular app', done:false}];
todoList.addTodo = function() {
todoList.todos.push({text:todoList.todoText, done:false});
todoList.todoText = '';
};
todoList.remaining = function() {
var count = 0;
angular.forEach(todoList.todos, function(todo) {
count += todo.done ? 0 : 1;
});
return count;
};
todoList.archive = function() {
var oldTodos = todoList.todos;
todoList.todos = [];
angular.forEach(oldTodos, function(todo) {
if (!todo.done) todoList.todos.push(todo);
});
};
});
todo.css
.done-true {
text-decoration: line-through;
color: grey;
}
一個(gè)深鏈接反應(yīng)了用戶在應(yīng)用中的哪個(gè)位置,這很有用,所以用戶可以把它存為書簽以及電子郵件鏈接,以在應(yīng)用內(nèi)部定位它。往返旅行的應(yīng)用程序會(huì)自動(dòng)獲得這個(gè)功能,但Ajax應(yīng)用程序按其性質(zhì)不會(huì)。AngularJS結(jié)合了深鏈接以及類似桌面應(yīng)用程序的行為的優(yōu)點(diǎn)。
客戶端表單驗(yàn)證是完美的用戶體驗(yàn)的一個(gè)重要的部分。AngularJS使你能夠聲明表單的有效性規(guī)則,而不需要書寫JavaScript代碼。從而事半功倍。
AngularJS提供了內(nèi)建的建在在XHR的頂層的服務(wù),以及多種多樣的使用第三方庫(kù)的其它后端。通過處理異步返回的數(shù)據(jù),Promise進(jìn)一步簡(jiǎn)化了您的代碼。在這個(gè)示例中,我們使用AngularFire庫(kù)以把一個(gè)Firebase后端接通到一個(gè)簡(jiǎn)單的Angular應(yīng)用上。
index.html
<!doctype html>
<html ng-app="project">
<head>
<script src="/attachments/image/wk/angularjs/angular.min.js"></script>
<script src="/attachments/image/wk/angularjs/angular-resource.min.js">
</script>
<script src="/attachments/image/wk/angularjs/angular-route.min.js">
</script>
<script src="/attachments/image/wk/angularjs/firebase.js"></script>
<script src="/attachments/image/wk/angularjs/angularfire.min.js"></script>
<link rel="stylesheet" href="bootstrap.css">
<script src="project.js"></script>
</head>
<body>
<h2>JavaScript Projects</h2>
<div ng-view></div>
</body>
</html>
bootstrap.css
// Uncomment this in Plunker or JSFiddle: @import '//netdna.bootstrapcdn.com/twitter-bootstrap/2.0.4/css/bootstrap-combined.min.css';
project.js
angular.module('project', ['ngRoute', 'firebase'])
.value('fbURL', 'https://ng-projects-list.firebaseio.com/')
.service('fbRef', function(fbURL) {
return new Firebase(fbURL)
})
.service('fbAuth', function($q, $firebase, $firebaseAuth, fbRef) {
var auth;
return function () {
if (auth) return $q.when(auth);
var authObj = $firebaseAuth(fbRef);
if (authObj.$getAuth()) {
return $q.when(auth = authObj.$getAuth());
}
var deferred = $q.defer();
authObj.$authAnonymously().then(function(authData) {
auth = authData;
deferred.resolve(authData);
});
return deferred.promise;
}
})
.service('Projects', function($q, $firebase, fbRef, fbAuth) {
var self = this;
this.fetch = function () {
if (this.projects) return $q.when(this.projects);
return fbAuth().then(function(auth) {
var deferred = $q.defer();
var ref = fbRef.child('projects-fresh/' + auth.auth.uid);
var $projects = $firebase(ref);
ref.on('value', function(snapshot) {
if (snapshot.val() === null) {
$projects.$set(window.projectsArray);
}
self.projects = $projects.$asArray();
deferred.resolve(self.projects);
});
//Remove projects list when no longer needed.
ref.onDisconnect().remove();
return deferred.promise;
});
};
})
.config(function($routeProvider) {
var resolveProjects = {
projects: function (Projects) {
return Projects.fetch();
}
};
$routeProvider
.when('/', {
controller:'ProjectListController as projectList',
templateUrl:'list.html',
resolve: resolveProjects
})
.when('/edit/:projectId', {
controller:'EditProjectController as editProject',
templateUrl:'detail.html',
resolve: resolveProjects
})
.when('/new', {
controller:'NewProjectController as editProject',
templateUrl:'detail.html',
resolve: resolveProjects
})
.otherwise({
redirectTo:'/'
});
})
.controller('ProjectListController', function(projects) {
var projectList = this;
projectList.projects = projects;
})
.controller('NewProjectController', function($location, projects) {
var editProject = this;
editProject.save = function() {
projects.$add(editProject.project).then(function(data) {
$location.path('/');
});
};
})
.controller('EditProjectController',
function($location, $routeParams, projects) {
var editProject = this;
var projectId = $routeParams.projectId,
projectIndex;
editProject.projects = projects;
projectIndex = editProject.projects.$indexFor(projectId);
editProject.project = editProject.projects[projectIndex];
editProject.destroy = function() {
editProject.projects.$remove(editProject.project).then(function(data) {
$location.path('/');
});
};
editProject.save = function() {
editProject.projects.$save(editProject.project).then(function(data) {
$location.path('/');
});
};
});
list.html
<input type="text" ng-model="projectList.search" class="search-query" id="projects_search"
placeholder="Search">
<table>
<thead>
<tr>
<th>Project</th>
<th>Description</th>
<th><a href="#/new"><i class="icon-plus-sign"></i></a></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="project in projectList.projects | filter:projectList.search | orderBy:'name'">
<td><a ng-href="{{project.site}}" target="_blank">{{project.name}}</a></td>
<td>{{project.description}}</td>
<td>
<a ng-href="#/edit/{{project.$id}}"><i class="icon-pencil"></i></a>
</td>
</tr>
</tbody>
</table>
detail.html
<form name="myForm">
<div class="control-group" ng-class="{error: myForm.name.$invalid && !myForm.name.$pristine}">
<label>Name</label>
<input type="text" name="name" ng-model="editProject.project.name" required>
<span ng-show="myForm.name.$error.required && !myForm.name.$pristine" class="help-inline">
Required {{myForm.name.$pristine}}</span>
</div>
<div class="control-group" ng-class="{error: myForm.site.$invalid && !myForm.site.$pristine}">
<label>Website</label>
<input type="url" name="site" ng-model="editProject.project.site" required>
<span ng-show="myForm.site.$error.required && !myForm.site.$pristine" class="help-inline">
Required</span>
<span ng-show="myForm.site.$error.url" class="help-inline">
Not a URL</span>
</div>
<label>Description</label>
<textarea name="description" ng-model="editProject.project.description"></textarea>
<br>
<a href="#/" class="btn">Cancel</a>
<button ng-click="editProject.save()" ng-disabled="myForm.$invalid"
class="btn btn-primary">Save</button>
<button ng-click="editProject.destroy()"
ng-show="editProject.project.$id" class="btn btn-danger">Delete</button>
</form>
指令是一個(gè)獨(dú)有而且強(qiáng)大的功能,只在Angular中可用。指令使你能夠發(fā)明新的HTML句法、專針對(duì)于你的應(yīng)用程序。
我們使用指令以創(chuàng)建可重復(fù)使用的組件。組件允許你隱藏復(fù)雜的DOM結(jié)構(gòu)、CSS以及行為。這使你能夠?qū)W⒂趹?yīng)用程序要做什么,或者單獨(dú)的應(yīng)用程序看起來如何。
嚴(yán)肅的應(yīng)用程序的一個(gè)重要組成部分是本地化。AngularJS的本地探知篩選器以及阻塞指令使你能夠建立屏蔽,使你的應(yīng)用程序在所有的地方都可用。
index.html
<!doctype html>
<html ng-app="app">
<head>
<script src="https://atts.w3cschool.cn/attachments/image/wk/angularjs/angular.min.js"></script>
<script src="components.js"></script>
<script src="app.js"></script>
<link rel="stylesheet" href="bootstrap.css">
</head>
<body>
<tabs>
<pane title="Localization">
Date: {{ '2012-04-01' | date:'fullDate' }} <br>
Currency: {{ 123456 | currency }} <br>
Number: {{ 98765.4321 | number }} <br>
</pane>
<pane title="Pluralization">
<div ng-controller="BeerCounter">
<div ng-repeat="beerCount in beers">
<ng-pluralize count="beerCount" when="beerForms"></ng-pluralize>
</div>
</div>
</pane>
</tabs>
</body>
</html>
components.js
angular.module('components', [])
.directive('tabs', function() {
return {
restrict: 'E',
transclude: true,
scope: {},
controller: function($scope, $element) {
var panes = $scope.panes = [];
$scope.select = function(pane) {
angular.forEach(panes, function(pane) {
pane.selected = false;
});
pane.selected = true;
}
this.addPane = function(pane) {
if (panes.length == 0) $scope.select(pane);
panes.push(pane);
}
},
template:
'<div class="tabbable">' +
'<ul class="nav nav-tabs">' +
'<li ng-repeat="pane in panes" ng-class="{active:pane.selected}">'+
'<a href="" ng-click="select(pane)">{{pane.title}}</a>' +
'</li>' +
'</ul>' +
'<div class="tab-content" ng-transclude></div>' +
'</div>',
replace: true
};
})
.directive('pane', function() {
return {
require: '^tabs',
restrict: 'E',
transclude: true,
scope: { title: '@' },
link: function(scope, element, attrs, tabsController) {
tabsController.addPane(scope);
},
template:
'<div class="tab-pane" ng-class="{active: selected}" ng-transclude>' +
'</div>',
replace: true
};
})
app.js
angular.module('app', ['components'])
.controller('BeerCounter', function($scope, $locale) {
$scope.beers = [0, 1, 2, 3, 4, 5, 6];
if ($locale.id == 'en-us') {
$scope.beerForms = {
0: 'no beers',
one: '{} beer',
other: '{} beers'
};
} else {
$scope.beerForms = {
0: '?iadne pivo',
one: '{} pivo',
few: '{} pivá',
other: '{} pív'
};
}
});
bootstrap.css
// Uncomment this in Plunker or JSFiddle: @import '//netdna.bootstrapcdn.com/twitter-bootstrap/2.0.4/css/bootstrap-combined.min.css';
在AngularJS依賴性注入允許你聲明式地描述你的應(yīng)用程序是如何連線的。這意味著你的應(yīng)用程序不需要main()方法,該方法通常是一個(gè)難以維護(hù)的大堆雜。依賴性的注入也是AngularJS的一個(gè)核心。這意味著任何不適合你的需要的組件可以輕松替換掉。
AngularJS設(shè)計(jì)為從根基開始都是可測(cè)試的。它鼓勵(lì)行為與視圖分離、用預(yù)綁定來模擬、充分利用依賴性注入。它還配備了端到端的場(chǎng)景分流道,它通過理解AngularJS的內(nèi)部運(yùn)作機(jī)制消除了測(cè)試片層分享。
更多建議: