zoukankan      html  css  js  c++  java
  • Live2D 看板娘

      本节我们会通过构建一个简单的笔记存储应用(可以载入并修改一组简单的笔记)来学习如何应用Angular的特性。这个应用用到的特性有:

    1. 在JSON文件中存储笔记
    2. 展示、创建、修改和删除笔记
    3. 在笔记中使用Markdown格式
    4. 同步编辑和预览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笔记格式的页面效果如下:

      

      笔记展示功能已完成,下一节来实现编辑功能。

       

  • 相关阅读:
    iOS开发——工厂模式
    iOS开发——单例模式
    iOS开发——设备信息小结(未完待续...)
    iOS开发——点击图片全屏显示
    关于Extjs Grid的选择问题
    Extjs form表单获得Values,表单控件没有Name,只有值时,如何获取后面的值
    Extjs Grid获取当前选中的行号
    让ToolBar的Item放置在右边(默认为左边)
    WBS探讨
    EXtjs为combo设置默认值
  • 原文地址:https://www.cnblogs.com/jiangtengteng/p/6057094.html
Copyright © 2011-2022 走看看