3.2.1 配置构建Angular应用——简单的笔记存储应用——展示功能
本节我们会通过构建一个简单的笔记存储应用(可以载入并修改一组简单的笔记)来学习如何应用Angular的特性。这个应用用到的特性有:
- 在JSON文件中存储笔记
- 展示、创建、修改和删除笔记
- 在笔记中使用Markdown格式
- 同步编辑和预览Markdown
本应用已经包含了基础的HTML和CSS代码,还有一个用Node写的简单的RESTful服务器,用于管理笔记,这样我们就可以专注于Angular而不是API。我们学习的重点是如何把Angular加入其中并学习它的重要特性。
3.2.1 获取项目文件
首先,我们需要来获取一下该项目的文件,可以通过git来获取,执行如下命令:
$ git clone https://github.com/ionic-in-action/chapter3.git(克隆chapter3仓库)
$ cd chapter3(切换到chapter3目录)
$ git checkout step1(检出step1标签)
(如果你不想使用git,可以直接下载文件:https://github.com/ionic-in-action/chapter3/archive/step1.zip)
3.2.2 启动开发服务器
由于这个项目搭载的是RESTful服务器,需要你掌握一些NodeJS的知识。在项目server.js文件中可以看到一个简单的RESTful服务器,它是基于Express.js框架开发的,这样做的原因是你需要长期管理笔记,通过RESTful API可以让应用阅读、创建、编辑和删除列表中的笔记。服务器还可以通过HTTP请求把文件载入浏览器,ionic serve就是通过这种方式来运行你的Ionic应用的。
需要注意的是:
- 服务器运行在3000端口上;
- 服务器会接受请求,根据URL和HTTP方法来修改列表中的笔记;
- 服务器使用JSON文件来作为数据库(data/notes.json),你可以根据自己的情况使用其他的数据库;
如果服务器不能运行,则说明你缺少一些必备的node包,解决方法,在终端中进入项目目录,运行$ npm install,npm会检查依赖列表并下载依赖。
然后输入命令$ node server来启动服务器,如果需要终止服务器可以按Ctrl+S或者直接关闭命令窗口。
运行后的基础模板如下图所示:
3.2.3 创建Angular应用
Angular开发简单来说就是用JavaScript创建一个Angular应用并在HTML中使用它。Angular和DOM紧密结合,所以你可以把一个Angular应用严格限制在一个DOM元素及其子元素中。在本例中使用的是<html>元素,所有Angular可以访问整个页面。Ionic通常使用的是<body>元素。
首先,你必须要先载入Angular库,然后要创建一个Angular应用,你需要在一个元素上使用ngApp指令并声明应用名称。打开index.html文件,并添加ngApp指令:
<html lang="en" ng-app="App">
现在,你已经把一个名为App的Angular应用附加到了HTML根元素上。这样Angular就可以访问整个DOM,不过你也可以把它附加到<body>标签中。我们建议把它放在<html>或者<body>元素中。
上面我们只是添加了ngApp的指令,还没有在JavaScript中声明这个应用,下面我们来完成这一步。Angular有一套模板系统,用来封装程序代码。声明新模块时,你需要提供名字和一个数组,其中包含所有依赖。Ionic本身也是一个Angular模块。Angular模块的声明方式如下,创建一个新文件js/app.js并写入下面的代码:
angular.module('App',[]);
最后,在index.html文件</body>标签前添加一个<script>标签来载入Angular模块:
<script src="js/app.js"></script>
你现在已经在页面中声明并载入了一个最基本的Angular应用。angular.module()方法会创建模块并把它附加到ngApp所属的DOM元素中。这是最基本的Angular应用,实际上它现在没有任何功能。所有的Angular应用都是用这样的方式定义的。
3.2.4 添加控制器
控制器:控制数据和业务逻辑
我们需要添加一个控制器来控制应用中多个部分的业务逻辑,它不会改变浏览器中应用的样子,因为控制器只负责管理数据,不影响应用的视觉效果,不过我们需要在管理视觉元素之前搞定控制器。添加控制器之后,它就可以访问页面中的某个特定区域。
下面我们来声明一个简单的控制器。首先你需要引用App模块并使用控制器方法来声明一个控制器。需要传入控制器的名字以及一个包含控制器逻辑的函数。创建文件js/editor.js:
//编辑控制器 js/editor.js
angular.module('App') //引入App模块并把它引入这个控制器中
.controller('EditorController',function($scope){ //声明EditorController控制器,传入一个包含依赖列表的函数
$scope.state={ //创建模型的值并存储到$scope中
editing:false
};
});
这个控制器现在非常简单,只是创建了一个简单的模型state。$scope服务被注入,所以你可以设置它的属性。记住,$scope中的值被称为模型,可以在视图中访问。
现在修改index.html文件,把控制器加入应用中,在</body>前引入editor.js文件:
<script src="js/editor.js"></script>
最后将控制器附加到DOM中。这会给控制器创建一个新的子作用域。我们需要用一条Angular指令来盛勇控制器被附加的位置:
<div class="container" ng-controller="EditorController">
注:$开头的服务
Angular中的服务以$符号开头,Ionic的服务也是如此。以$开头的服务,按惯例是Angular核心服务或者Ionic服务。
3.2.5 加载数据并将数据显示在应用中
加载数据:使用控制器来加载数据并显示在视图中
下面我们来加载数据并把它显示到应用中,在应用的基础模板左侧已经有一个创建好的空的笔记列表。然后我们加入一些简单的笔记,更新控制器从而把数据载入应用。要实现这个功能,需要使用Angular的$http服务,通过$http服务来请求Node服务器的数据。我们来具体操作一下:
先修改控制器,通过HTTP请求访问服务器的笔记服务并把返回的数据赋值给作用域。打开js/editor.js文件,更新代码:
angular.module('App')
.controller('EditorController', function ($scope,$http) { //把$http服务注入控制器
$scope.editing = true; $http.get('/notes').success(function(data){ //使用$http.get加载笔记,如果成功,使用法内的数据
$scope.notes = data; //把从http返回的数据赋值给$scope
}).error(function(err){ //处理错误,存储错误
$scope.error = 'Could not load notes';
});
});
注意控制器函数中可以给函数声明任意数量的参数,Angular会通过名字来定位服务并注入控制器。上面代码中$http的使用方法叫做依赖注入(DI),是Angular一个非常强大的特性,可以让你的控制器使用各种服务。由于Angular的服务并不是全局的,所以必须先注入再使用。
这时我们启动服务,但是在页面上看不到任何数据,而我们访问http://localhost:3000/notes,发现json数据可以访问没有问题,那是为什么我们看不到数据呢?因为我们需要更新index.html模板文件,用Angular指令把数据从$scope中显示出来,对index.html文件,我们需要进行如下修改:
<div class="col-sm-3">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><button class="btn btn-primary btn-xs pull-right">New</button> My Notes</h3>
</div>
<div class="panel-body">
<!-- ngIf会根据是否有笔记来判读是否把这个元素插入DOM -->
<p ng-if="!notes.length">No notes</p>
<ul class="list-group">
<!-- ngRepeat会循环每个笔记并显示笔记标题 -->
<li class="list-group-item" ng-repeat="note in notes">{{note.title}}><br />
<!-- 绑定显示日期,使用过滤器显示较短的日期 -->
<small>{{note.date | date:'short'}}</small></li>
</ul>
</div>
</div>
</div>
说明:模板中{{note.date | date:'short'}}有个| date:'short',这是一个过滤器,它会在不改动作用域值的前提下修改显示内容。在表达式中可以通过管道符来使用过滤器,过滤器可以串联,也就是说可以添加多个过滤器。
加载数据后的笔记截图:
3.2.6 处理选择笔记的单击事件
如果需要单独查看某条笔记,需要单击左侧列表笔记时,将他们显示在右侧。
使用ngClick可处理用户的单击事件,然后把笔记数据赋值给一个新的模型,用来进行显示,我们来打开模版index.html,修改笔记列表的部分,添加单击事件处理器:
<ul class="list-group">
<!-- ngRepeat会循环每个笔记并显示笔记标题;ngClick会调用view()并传入下标;添加ngClass,如果笔记被选中就添加active类 -->
<li class="list-group-item" ng-repeat="note in notes" ng-click="view($index)" ng-class="{active: note.id == content.id}">{{note.title}}><br />
<!-- 绑定显示日期,使用过滤器显示较短的日期 -->
<small>{{note.date | date:'short'}}</small></li>
</ul>
当单击笔记时,Angular会尝试调用$scope.view()函数,ngClass指令可以根据情况向元素添加css类。$index值时ngRepeat提供的特殊变量,被传入视图函数里,作用就是告诉你当前被使用的数组元素的下标,此处指的是被单击元素的下标。
下面我们来创建视图函数,打开editor.js文件,在控制器函数里添加视图函数:
$scope.view = function(index){ //声明一个名为view的新$scope方法,接受被点击元素的下标
$scope.editing = false; //把editing状态设置为false,因为此时用户要查看元素
$scope.content = $scope.notes[index]; //给content模型设置一个新模型,包含被单击的笔记
};
此时,当我们点击笔记时,click时间会触发控制器中view()方法,它会根据传入的下标值找到被点击的笔记,并将笔记内容赋值给新的content模型,同时,editing模型也会被设置为false。
3.2.7 更新模版显示被选择的笔记
此时点击笔记,右侧面板不会有变化,因为我们还没有修改右侧显示的面板,右侧面板有两种状态,一个是展示笔记,一个是编辑笔记,$scope.editing属性将决定显示哪个面板。再次打开index.html文件作如下修改:
<!-- ngHide会在本条件为真时隐藏头部,在这里editing为true的时候条件为真 -->
<div class="panel panel-default" ng-hide="editing">
<div class="panel-heading">
<!-- 把title绑定到头部 -->
<h3 class="panel-title">{{content.title}} <button class="btn btn-primary btn-xs pull-right">Edit</button></h3>
</div>
<!-- 把content绑定到正文 -->
<div class="panel-body">{{content.content}}</div>
<!-- 绑定笔记日期并把它传递给过滤器 -->
<div class="panel-footer">{{content.date | date:'short'}}</div>
</div>
<!-- ngShow会在条件为假时隐藏底部,在这里editing为false的时候条件为假 -->
<form name="editor" class="panel panel-default" ng-show="editing">
再次运行应用,此时单击笔记即可实现查看功能,如下图所示:
3.2.8 创建指令,解析Markdown格式的笔记
要实现把Markdown格式的文本转换为HTML,需要使用Showdown这个js库。
打开app.js文件,指令不是控制器的一部分,所以代码需要被存储到应用主文件中,具体代码如下:
//声明命令并命名为markdown
.directive('markdown',function(){
//创建showdown转换器,下面会用到
var converter = new Showdown.converter();
//命令会返回一个对象,用来声明命令的设置
return {
//声明自定义作用于,等待值被赋给markdown属性
scope:{
markdown:'@'
},
//声明link函数,它会把markdown转换成html
link:function(scope,element,attrs){
//使用作用于观察器来同步模型改动
scope.$watch('markdown',function(){
//把markdown转换成html并存入content变量
var content = converter.makeHtml(attrs.markdown);
//把转换好的html内容注入到元素内
element.html(content);
});
}
}
});
现在我们打开index.html文件,传入markdown内容:
<div class="panel-body" markdown="{{content.content}}"></div>
改为markdown笔记格式的页面效果如下:
笔记展示功能已完成,下一节来实现编辑功能。
3.2.1 配置构建Angular应用——简单的笔记存储应用——展示功能的更多相关文章
- 3.2.1 配置构建Angular应用——简单的笔记存储应用——编辑功能
本节我们会接着上节课的内容,继续来完成使用Angular来创建简单的笔记存储应用,上一节课,我们完成了笔记的展示功能,本节课,我们来完成编辑功能. 编辑主要是两个功能:编辑现有的笔记以及创建新笔记.首 ...
- 3.2 配置构建Angular应用——简单的笔记存储应用
本节我们会通过构建一个简单的笔记存储应用(可以载入并修改一组简单的笔记)来学习如何应用Angular的特性.这个应用用到的特性有: 在JSON文件中存储笔记 展示.创建.修改和删除笔记 在笔记中使用M ...
- android studio+grade配置构建
Android 构建系统编译应用资源和源代码,然后将它们打包成可供您测试.部署.签署和分发的 APK.android Studio 使用 Gradle 这一高级构建工具包来自动化执行和管理构建流程,同 ...
- jenkins配置构建执行状态
运行构建 在项目 左侧列表点击 “立即构建” ,在 “Build History” 列表中,会看到执行状态,蓝色圆点表示构建成功,红色圆点表示构建失败 点击 构建失败的任务(红色的小圆点).然后点击“ ...
- C# 构建XML(简单示例)
C# 构建XML的简单示例: var pars = new Dictionary<string, string> { {"url","https://www. ...
- Redis:安装、配置、操作和简单代码实例(C语言Client端)
Redis:安装.配置.操作和简单代码实例(C语言Client端) - hj19870806的专栏 - 博客频道 - CSDN.NET Redis:安装.配置.操作和简单代码实例(C语言Client端 ...
- win2008系统:iis配置备份和还原简单操作
(2013-09-26 16:33:22) 转载▼ 分类: 开发类 当我们电脑系统有大量的站点和虚拟目录的时候,电脑因为种种原因需要重做系统,那么重装系统后这些站点我们是否只能一个一个的添加,如果 ...
- Ubuntu下配置python完成爬虫任务(笔记一)
Ubuntu下配置python完成爬虫任务(笔记一) 目标: 作为一个.NET汪,是时候去学习一下Linux下的操作了.为此选择了python来边学习Linux,边学python,熟能生巧嘛. 前期目 ...
- Log4j简单学习笔记
log4j结构图: 结构图展现出了log4j的主结构.logger:表示记录器,即数据来源:appender:输出源,即输出方式(如:控制台.文件...)layout:输出布局 Logger机滤器:常 ...
随机推荐
- HDU-4791-Alice‘s Print Service
分析: 1.由于价格是递减的,所以可能出现si*pi>sj*pj(j>i).所以要有一个数组来储存当前端点的最小值. 2.然后二分查找当前的si,比较q*p[i]和M[i+1].不过在这之 ...
- UVa-1585-得分
#include <stdio.h> #include <string.h> int main() { char s[100]; int T; scanf("%d&q ...
- Openjudge-百练-4013-踩方格
这题目是一道深搜的题目,我们写一个递归函数叫Ways(int i, int j ,int n),i j就是当前所处的坐标,我们设置一个visited数组,简称 V . 对于这个数组,首先初始化为零,然 ...
- PHP中的预定义常量、类常量和魔术常量的区别
PHP 向它运行的任何脚本提供了大量的预定义常量.不过很多常量都是由不同的扩展库定义的,只有在加载了这些扩展库时才会出现,或者动态加载后,或者在编译时已经包括进去了. 对于一些基本的常量是这些常量在 ...
- img元素srcset属性浅析
img srcset 属性 img 元素的 srcset 属性用于浏览器根据宽.高和像素密度来加载相应的图片资源. 属性格式:图片地址 宽度描述w 像素密度描述x,多个资源之间用逗号分隔.例如: &l ...
- Chrome浏览器 v68.0.3440.106 正式版怎么样?
谷歌浏览器Google Chrome稳定版迎来v68正式版第三个维护版本发布,详细版本号为v68.0.3440.106,上一个正式版v68.0.3440.84发布于8月1日,时隔8天Google又发布 ...
- css中background-image背景图片路径设置
web项目中经常会用到background-image:url(),很多小伙伴不知道该怎么写需要的图片路径. 在此之前先要知道几个重要的东东: / 项目根目录 这个不用多说,就是程序 ...
- 什么样的经历,才能领悟成为架构师? >>>
什么样的经历,才能领悟成为架构师? >>> 本文主要分析 SpringBoot 的启动过程. SpringBoot的版本为:2.1.0 release,最新版本. 一.时序图 还是老 ...
- 基于神经网络的embeddding来构建推荐系统
在之前的博客中,我主要介绍了embedding用于处理类别特征的应用,其实,在学术界和工业界上,embedding的应用还有很多,比如在推荐系统中的应用.本篇博客就介绍了如何利用embedding来构 ...
- 字典树模板题 POJ 2503
#include <cstdio> #include <cstring> ],fr[]; int st; struct Tire{ ]; ]; }node[]; void in ...