Nodejs之MEAN栈开发(五)---- Angular入门与页面改造
2016-07-08 08:21
666 查看
这个系列一共会涉及两个JavaScript框架的讲解,一个是Express用做后端,一个是Angular用于前端。和Express一样,Angular分离内容,处理视图、数据和逻辑。和MVC模式很相似,但其实Angular定义是MVW框架,W代表(what ever works for you)。意味着它可以是控制器或者视图模型,或者服务,就看你怎么定义的。这一节会介绍基本的Angular知识;然后改造我们之前做的页面;并且调用之前的定义的api来获取数据。
Angular的数据绑定是指视图的改变会更新模型,而模型的改变也会更新视图。
View Code
并注册:
第三步:更新视图(index.jade)
我们将homeController加载.page这个元素上。在第二步里面,我们定义了一个Data的模型,其实是一个数组集合,这里用
循环输出。代替了jade的each语法:‘each topic in topics‘,和jade不同的是,jade的循环语句位于.topiclist的上方,而Angular的repeat指令要添加在你需要重复的元素了。然后还要注意的是,所有的元素内容中的{{}}前的等号要拿掉,换成空格赋值的语法(等号表示变量,空格表示是字符串),不然无法输出。再注意一个是img的src要用ng-src,不然不能输出url。这个时候运行,已经可以看见输出了:
属性的后面跟上|号和一个名字,这就叫过滤器(filter),故名思议,通过特定的规则,将源数据转换成需要的数据格式。这里的formdate的定义是:
形式上和注册controller是一样,不同的是,filter需要返回一个函数。其实Angular自带一些数据格式,比如data,currency等。如下
先模拟的个数据,在homeController中加入models
然后定义一个ratings指令:
并注册,
在视图上输出。这里有一个注意的地方,html属性是大小写不敏感的,驼峰式的命名需要用转换一下,也就是ratingStars 匹配的是rating-stars,即大写字母转成'-' 加小写字母。
页面上会输出4和5.这自然还不能满足我们的要求。有两点:1属性名限制的太死了,不能总是'book.rating'。2是需要把数字变成星星。第一个问题是一个作用域的问题,需要创建一个作用域变量。
创建了一个thisRating的作用域变量,而'=rating'告诉Angular去匹配带有‘rating'的属性。然后在Angular文件夹下创建一个rating-stars.html。
然后用templateUrl指向这个片段
在视图上运用:
得到星星
指令的这个scope显得不是很方便。最开始用模拟数据是因为 small(rating-stars) 这种写法不识别jade中的循环(each book in books)中的book对象,而'p(rating-stars, rating=book.rating)'又能识别。
创建一个方法,命名为topicData,用来返回topic数据。
注册service:
使用service:
不要忘记在参数里面加入需要调用的服务名称。到现在完成了一个服务的调用,接下来我们从api来获取数据。JavaScript发送http请求不是什么新鲜事了,Jquery的ajax,node里面的request模块,而Angular有一个自带的服务:$http,用来处理请求。接下来就用它来请求api。
$http有一个get方法,参数就是一个url。这里调用我们在第三节定义好的api。--> 使用Mongoose创建模型及API
这是一个异步的方法,所以还需要改造Controller中的代码:
这时候运行,可以看到全部的数据了。
异步加载数据的一个问题是用户刚打开页面的时候可能是一片空白,所以加一个过渡的内容好一点。
页面加一个:
这样避免出现一个短时间的空白。
小结:这一节我们体验了Angular的数据绑定模式,并学习了如何定义并使用module、Controller、directive、filter和service。简单了改造了首页,将Express的一部分工作转移到了前端。其实涉及到Angular的每一个部分都不够深入,只是按需分配,用到多少就讲多少。我觉得这样循序渐进的比较好。下一节将介绍用Angular做一个单页应用(SPA),讲解Angular路由等知识。
Angular的数据绑定是指视图的改变会更新模型,而模型的改变也会更新视图。
var topics = [ { title: "书山有路第十一期:程序员修炼之道-第八章-注重实效的项目--第二十二天", type: "读书", visitedCount: 80, commentCount: 2, createdOn: '2016/7/05 21:32', author: 'stoneniqiu', img: 'http://upload.jianshu.io/users/upload_avatars/133630/d5370e672fd4.png?imageMogr/thumbnail/90x90/quality/100' }, { title: "《明朝那些事儿》之闲言散语", type: "书评", visitedCount: 180, commentCount: 20, createdOn: '2016/5/15 21:32', author: '卡卡卡萨布兰卡 ', img: 'http://upload.jianshu.io/users/upload_avatars/1675188/2d0810ccc03d.jpg?imageMogr/thumbnail/90x90/quality/100' }, { title: "有《程序员修炼之道》高清版吗?", type: "求书", visitedCount: 90, commentCount: 1, createdOn: '2016/5/15 21:32', author: '吾不知 ', img: 'http://upload.jianshu.io/users/upload_avatars/1125491/3910f3825f73.jpg?imageMogr/thumbnail/90x90/quality/100', }];
View Code
var homeController = function($scope) { $scope.data = topics; };
并注册:
angular.module('readApp') .controller('homeController', homeController)
第三步:更新视图(index.jade)
.col-md-9.page(ng-controller="homeController") .row.topictype a.label.label-info(href='/') 全部 a(href='/') 读书 a(href='/') 书评 a(href='/') 求书 a(href='/') 求索 .row.topiclist(ng-repeat='topic in data') img(ng-src='{{topic.img}}') span.count i.coment {{topic.commentCount}} i / i {{topic.visitedCount}} span.label.label-info {{topic.type}} a(href='/') {{topic.title}} span.pull-right{{topic.createdOn|formdate}} a.pull-right.author(href='/') {{topic.author}}
我们将homeController加载.page这个元素上。在第二步里面,我们定义了一个Data的模型,其实是一个数组集合,这里用
(ng-repeat='topic in data')
循环输出。代替了jade的each语法:‘each topic in topics‘,和jade不同的是,jade的循环语句位于.topiclist的上方,而Angular的repeat指令要添加在你需要重复的元素了。然后还要注意的是,所有的元素内容中的{{}}前的等号要拿掉,换成空格赋值的语法(等号表示变量,空格表示是字符串),不然无法输出。再注意一个是img的src要用ng-src,不然不能输出url。这个时候运行,已经可以看见输出了:
4.filter
大家可能留意到,上面有这样一段代码:{{topic.createdOn|formdate}}
属性的后面跟上|号和一个名字,这就叫过滤器(filter),故名思议,通过特定的规则,将源数据转换成需要的数据格式。这里的formdate的定义是:
var formdate = function() {
return function(dateStr) {
var date = new Date(dateStr);
var d = date.getDate();
var monthNames = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"];
var m = monthNames[date.getMonth()];
var y = date.getFullYear();
var output = y + '-' + m + '-' + d;
return output;
};
};
angular.module('readApp') .controller('homeController', homeController)
.filter('formdate', formdate)
形式上和注册controller是一样,不同的是,filter需要返回一个函数。其实Angular自带一些数据格式,比如data,currency等。如下
<div>{{50.25|currency }}</div> $50.25 <div>{{50.25|currency:'¥' }}</div> ¥50.25
<div>{{ "Let's shout" | uppercase }}</div> <!-- 输出: LET’S SHOUT --> {{ timestamp | date:"d MMM yyyy" }} <!-- 输出: 21 Aug 2014 -->
5.directive
指令主要是用来创建html片段,一个html代码片段可以被多个不同的controller和view使用,这容易保持一致性且容易维护。这些片段运行在Angular应用的上下文中,照样可以使用数据绑定,而且浏览器可以缓存这些指令为html文件,当用户在不同的view来回切换时,这有利于加速应用。接下来演示如何添加一个指令,改造之前显示星星的部分(切换到books.jade)。先模拟的个数据,在homeController中加入models
$scope.models = [{ rating: 4 }, { rating: 5 }];
然后定义一个ratings指令:
var ratingStars = function () { return { template : "{{book.rating}}", }; };
并注册,
angular.module('readApp') .controller('homeController', homeController)
.filter('formdate', formdate)
.directive('ratingStars', ratingStars)
在视图上输出。这里有一个注意的地方,html属性是大小写不敏感的,驼峰式的命名需要用转换一下,也就是ratingStars 匹配的是rating-stars,即大写字母转成'-' 加小写字母。
p(ng-repeat='book in models') small(rating-stars)
页面上会输出4和5.这自然还不能满足我们的要求。有两点:1属性名限制的太死了,不能总是'book.rating'。2是需要把数字变成星星。第一个问题是一个作用域的问题,需要创建一个作用域变量。
return { scope: { thisRating : '=rating' }, template : "{{ thisRating }}" };
创建了一个thisRating的作用域变量,而'=rating'告诉Angular去匹配带有‘rating'的属性。然后在Angular文件夹下创建一个rating-stars.html。
<span class="glyphicon glyphicon-star{{ thisRating<1 ? '-empty' : ''}}"></span> <span class="glyphicon glyphicon-star{{ thisRating<2 ? '-empty' : ''}}"></span> <span class="glyphicon glyphicon-star{{ thisRating<3 ? '-empty' : ''}}"></span> <span class="glyphicon glyphicon-star{{ thisRating<4 ? '-empty' : ''}}"></span> <span class="glyphicon glyphicon-star{{ thisRating<5 ? '-empty' : ''}}"></span>
然后用templateUrl指向这个片段
var ratingStars = function () { return { scope: { thisRating : '=rating' }, templateUrl: '/angular/rating-stars.html' }; };
在视图上运用:
p(rating-stars, rating=book.rating)
得到星星
指令的这个scope显得不是很方便。最开始用模拟数据是因为 small(rating-stars) 这种写法不识别jade中的循环(each book in books)中的book对象,而'p(rating-stars, rating=book.rating)'又能识别。
6.service
service在Angular中应用比较多,大部分的应用逻辑都可以用service来实现,而且可以给多个controller调用。接下来将controller的中数据移到一个service中去,然后让controller调用service。创建一个方法,命名为topicData,用来返回topic数据。
var topicData = function ($http) { return topics; };
注册service:
.service('topicData', topicData);
使用service:
var homeController = function($scope, topicData) { $scope.data = topicData; };
不要忘记在参数里面加入需要调用的服务名称。到现在完成了一个服务的调用,接下来我们从api来获取数据。JavaScript发送http请求不是什么新鲜事了,Jquery的ajax,node里面的request模块,而Angular有一个自带的服务:$http,用来处理请求。接下来就用它来请求api。
var topicData = function ($http) { return $http.get('/api/topics'); };
$http有一个get方法,参数就是一个url。这里调用我们在第三节定义好的api。--> 使用Mongoose创建模型及API
这是一个异步的方法,所以还需要改造Controller中的代码:
var homeController = function ($scope, topicData) { topicData.success(function (data) { console.log(data); $scope.data = data; }).error(function (e) { console.log(e); }); };
这时候运行,可以看到全部的数据了。
异步加载数据的一个问题是用户刚打开页面的时候可能是一片空白,所以加一个过渡的内容好一点。
var homeController = function ($scope, topicData) { $scope.message = "loading..."; topicData.success(function (data) { console.log(data); $scope.message = data.length > 0 ? "" : "暂无数据"; $scope.data = data; }).error(function (e) { console.log(e); $scope.message = "Sorry, something's gone wrong "; }); };
页面加一个:
.error {{ message }}
这样避免出现一个短时间的空白。
小结:这一节我们体验了Angular的数据绑定模式,并学习了如何定义并使用module、Controller、directive、filter和service。简单了改造了首页,将Express的一部分工作转移到了前端。其实涉及到Angular的每一个部分都不够深入,只是按需分配,用到多少就讲多少。我觉得这样循序渐进的比较好。下一节将介绍用Angular做一个单页应用(SPA),讲解Angular路由等知识。
相关文章推荐
- js中nodeName nodeType nodeValue的用法和区别
- Nodejs学习路线图
- Node.js 文件夹目录结构创建实例代码
- ElasticSearch 单表(json格式)导入之nodejs+elasticdump运用
- 利用nvm自由切换Node.js版本
- 19. Remove Nth Node From End of List
- LeetCode 第 19 题 (Remove Nth Node From End of List)
- LeetCode 第 19 题 (Remove Nth Node From End of List)
- DOM之parentNode与offsetParent
- nodejs npm常用命令
- Leetcode Delete Node in a Linked List
- 在github上搭建blog(基于Node.js的Hexo+next)
- Node.js:express (post get querystring json sendFile)
- 原生JS 循环Nodelist Dom列表的4种方式
- nodejs 设计思想杂记四 异步控制流模式
- Nodejs学习路线图
- Nodejs中关于类的创建
- LeetCode 19. Remove Nth Node From End of List详解
- 关于nodejs中使用命令行启动报错的问题
- 5. node.js 的 模块(Module)和包(Package)