序言
本章將通過angular默認的ng-route組件來復用視圖與前端的路由控制。
上一個章節(jié)的完成圖
本章目的
在底部增加一個狀態(tài)的過濾屈暗,可以分別顯示“全部”妨蛹,“未完成”和“已完成”不同狀態(tài)下的清單屏富。
1. 使用ng-route復用視圖
1.1 調(diào)整index.html
首先我們先來審閱一下當年的index.html代碼
<!doctype html>
<html lang="en" data-framework="angularjs">
<head>
<meta charset="utf-8">
<title>AngularJS ? TodoMVC</title>
<link rel="stylesheet" href="node_modules/todomvc-common/base.css">
<link rel="stylesheet" href="node_modules/todomvc-app-css/index.css">
</head>
<body ng-app="todomvc" ng-controller="TodoController as vm">
<section id="todoapp">
<header id="header">
<h1>todos</h1>
<form id="todo-form" ng-submit="vm.addTask()">
<input id="new-todo" placeholder="添加新的任務?" ng-model="vm.newTask" autofocus>
</form>
</header>
<section id="main" ng-cloak>
<ul id="todo-list">
<li ng-repeat="task in vm.tasks" ng-class="{completed: task.completed, editing: task === vm.editedTask}">
<div class="view">
<input class="toggle" type="checkbox" ng-model="task.completed">
<label ng-dblclick="vm.editTask(task)">{{task.title}}</label>
<button class="destroy" ng-click="vm.removeTask(task)"></button>
</div>
<form>
<input class="edit" ng-trim="false" ng-model="task.title" >
</form>
</li>
</ul>
</section>
</section>
<script src="node_modules/angular/angular.js"></script>
<script src="node_modules/angular-route/angular-route.js"></script>
<script src="js/app.js"></script>
<script src="js/controllers/todo.controller.js"></script>
</body>
</html>
body標簽的section標簽內(nèi)的內(nèi)容才是有有邏輯并且可分離的視圖代碼。
故我們使用ng-route來規(guī)劃前端的url分發(fā)控制與對應的蛙卤,通過對目標URL的撞他變化加載對應的視圖與控制器文件狠半。
1.2 分離業(yè)務視圖至partials/todo.html文件
我們將index.html代碼分離出來,新建一個partials/todo.html颤难,其內(nèi)容如下神年。
目錄結(jié)構(gòu)
<section id="todoapp">
<header id="header">
<h1>todos</h1>
<form id="todo-form" ng-submit="vm.addTask()">
<input id="new-todo" placeholder="添加新的任務?" ng-model="vm.newTask" autofocus>
</form>
</header>
<section id="main" ng-cloak>
<ul id="todo-list">
<li ng-repeat="task in vm.tasks" ng-class="{completed: task.completed, editing: task === vm.editedTask}">
<div class="view">
<input class="toggle" type="checkbox" ng-model="task.completed">
<label ng-dblclick="vm.editTask(task)">{{task.title}}</label>
<button class="destroy" ng-click="vm.removeTask(task)"></button>
</div>
<form>
<input class="edit" ng-trim="false" ng-model="task.title" >
</form>
</li>
</ul>
</section>
</section>
消除這段代碼后整個index.html就只剩下相關(guān)的入口及配置信息代碼就變得干凈很多。
因為使用了ng-route之后控制器的初始化就不需要我們顯式的寫在視圖中行嗤。故我們刪除掉body標簽中的ng-controller屬性已日。
<!--
<body ng-app="todomvc" ng-controller="TodoController as vm">
-->
<body ng-app="todomvc">
最后在body標簽下引入ng-route的動態(tài)視圖指令ng-view
<body ng-app="todomvc">
<ng-view />
<script src="node_modules/angular/angular.js"></script>
<script src="node_modules/angular-route/angular-route.js"></script>
<script src="js/app.js"></script>
<script src="js/controllers/todo.controller.js"></script>
</body>
1.3 引入route配置信息
我們重新編輯app.js文件增加根路徑的視圖與控制器加載邏輯。
(function(){
'use strict';
angular.module('todomvc', ['ngRoute'])
.config(routerConfig);
routerConfig.$inject = ['$routeProvider'];
function routerConfig($routeProvider){
$routeProvider
.when('/',{
controller: 'TodoController',
templateUrl: 'partials/todo.html',
controllerAs: 'vm'
})
};
})();
routeConfig中操作$routeProvider服務栅屏,向其添加路由規(guī)則飘千。
.when('/',{
controller: 'TodoController', //控制器
templateUrl: 'partials/todo.html', //視圖
controllerAs: 'vm' // 控制器As的別名語法堂鲜,Angular1.2以后提倡的語法
})
這樣我們就讓angular在客戶端維護了一個可以根據(jù)url做出影響的前端運行時環(huán)境,這個時候我們重新在瀏覽器刷新地址則發(fā)現(xiàn)應用與之前是沒區(qū)別的护奈,唯一的區(qū)別是路徑上多了一個#符號缔莲。
默認模式下,瀏覽器都只訪問index.html的入口頁 /#/之后的路徑為ng-route控制的url部分霉旗,這樣即使前端便可以進行無刷新的頁面url的跳轉(zhuǎn)操作了痴奏。
2. 向應用中添加底部狀態(tài)控制欄
這次我們希望通過不同的url來顯示不同的任務清單列表:
- 在/路徑下顯示所有狀態(tài)的任務清單
- 在/active路徑下顯示所有未完成的任務清單
- 在/completed路徑下顯示所有完成的任務清單
2.1 修改ng-route
添加新/:status路由,將active于completed作為參數(shù)傳給controller做數(shù)據(jù)的篩選奖慌。
.when('/:status', {
controller: 'TodoController',
templateUrl: 'partials/todo.html',
controllerAs: 'vm'
})
2.2 在controller層獲取路由參數(shù)
我們在Controller層想要獲取路徑上的參數(shù)抛虫,則需要向Controller注入$routeParams服務,在通過$routeParams.paramName的形式便可以獲取對應的參數(shù)值简僧。
我們修改我們TodoController使其可以對不同的status狀態(tài)做出不同的過濾操作建椰。
首先,我們編寫一個函數(shù)可以根據(jù)不同的status值來過濾處理controller中的任務清單數(shù)組
function _filterDataByStatus(tasks,status){
if (status === 'active'){
return tasks.filter(function(task){
return (task.completed != true )
})
}else if(status === 'completed'){
return tasks.filter(function(task){
return (task.completed == true )
})
}else{
return tasks;
}
}
然后,調(diào)整TodoController中的初始化邏輯,通過$routeParam服務來獲取路徑中的status的值岛马。
function init(){
var tasks = [
{
title: "第一個任務",
completed: true
},
{
title: "第二個任務",
completed: false
}];
vm.status = $routeParams.status||"";
vm.tasks = _filterDataByStatus(tasks,vm.status)
}
我們額外聲明了一個vm.status變量用于記錄當前的status的值棉姐,用于模板中的底部狀態(tài)過濾標簽對當前激活的過濾條件做高亮顯示。
2.3 增加底部的狀態(tài)切換區(qū)域
我們在todo.html中增加一段新的footer標簽區(qū)域用于顯示底部的狀態(tài)切換的狀態(tài)標簽按鈕啦逆。
<footer id="footer" ng-show="vm.tasks.length" ng-cloak>
<span id="todo-count"><strong>{{remainingCount}}</strong>
<ng-pluralize count="remainingCount" when="{ one: 'item left', other: 'items left' }"></ng-pluralize>
</span>
<ul id="filters">
<li>
<a ng-class="{selected: vm.status == ''} " href="#/">All</a>
</li>
<li>
<a ng-class="{selected: vm.status == 'active'}" href="#/active">Active</a>
</li>
<li>
<a ng-class="{selected: vm.status == 'completed'}" href="#/completed">Completed</a>
</li>
</ul>
</footer>
底部有三個按鈕分別對應路徑"/","/active"與"/completed"伞矩。并根據(jù)vm.status使用ng-class來高亮顯示當前激活的過濾條件標簽。
2.4 測試應用
我們分別測試不同狀態(tài)下的清單顯示情況
2.4.1 默認顯示全部
2.4.2 待完成
2.4.3 已完成
2.5 問題
似乎看上去我們的過濾功能以前完成了夏志,但是我們可以添加一個新的任務乃坤,再進行條件過濾,這個時候則會發(fā)現(xiàn)新建的任務清單“不見了”沟蔑。
這是因為不同路由下的雖然為同名controller但是其中的實例變量還是會重新初始化湿诊。兩個Controller實例沒有進行數(shù)據(jù)的共享。
vm.tasks的賦值邏輯
var tasks = [
{
title: "第一個任務",
completed: true
},
{
title: "第二個任務",
completed: false
}];
vm.status = $routeParams.status||"";
//此處的進行雙向綁定
vm.tasks = _filterDataByStatus(tasks,vm.status)
在下一章的文章中我們將介紹Angular中常見幾種在controller中共享瘦材、傳遞數(shù)據(jù)的方法并選取一種來調(diào)整我們的代碼厅须。