angular_angularjs - CSDN
angular 订阅
Angular (通常是指 "Angular 2+" 或 "Angular v2 及更高版本")。是一个基于 TypeScript 的 开源 Web 应用框架, 由 Google 的 Angular 团队以及社区共同领导。Angular 是由 AngularJS 的同一个开发团队完全重写的。 展开全文
Angular (通常是指 "Angular 2+" 或 "Angular v2 及更高版本")。是一个基于 TypeScript 的 开源 Web 应用框架, 由 Google 的 Angular 团队以及社区共同领导。Angular 是由 AngularJS 的同一个开发团队完全重写的。
信息
外文名
Angular
别    名
Angular
中文名
Angular
广告历程
在设计上,Angular 是 AngularJS 的完全重写。最初,团队将这份 AngularJS 的重写版本称为 “Angular 2”,但这在开发人员之间引起了混乱。为了明确起见,该团队宣布应该为这两个框架分别使用各自的术语,其中 “AngularJS” 专指 1.X 版本,而不带 “JS” 的 “Angular” 则专指版本2及更高版本。在2014年10月22~23日的 ng-Europe 会议上发布了Angular 2.0。2.0 版的重大变化在开发人员之间引起了很大争议。 2015年4月30日,Angular 开发组宣布 Angular 2 从 Alpha 推进到 Developer Preview。 Angular 2 于2015年12月推进至 Beta 版, 并于 2016年5月发布了首个 rc 版本。其最终版本于2016年9月14日发布。2016年12月13日发布了 Angular 4,它跳过了版本号 3,以免由于路由模块的版本的未和其它模块对齐而造成混淆(路由模块在之前已经作为 v3.3.0 发布了)。 其最终版本于2017年3月23日发布。 Angular 4 向后兼容 Angular2。Angular 4.3 版是次要版本,这意味着它没有破坏性变更,是 4.xx 的直接替代品。版本 4.3 中的特性Angular 5 于2017年11月1日发布。 Angular 5 的主要改进包括对渐进式 Web 应用的支持、一个构建优化器,以及一些与 Material Design 相关的改进。Angular 6 于2018年5月4日发布。这是一个主版本,其改进重点不在于底层框架,而在于工具链,其目的是让工具链能在将来与 Angular 一起快速发展,改进点主要包括:ng update、ng add、Angular Elements、Angular Material + CDK 组件库、Angular Material 初学者组件、CLI 工作空间、库支持、服务提供商的摇树优化、动画性能改进,以及 RxJS v6。Angular 7 于2018年10月18日发布。其升级主要集中在 Angular Material & CDK、虚拟滚动、选择框在无障碍方面的改进、支持对符合 Web 标准的自定义元素进行内容投影,以及对 Typescript 3.1、RxJS 6.3、Node 10 (仍然支持 Node 8) 的依赖库更新。Angular 8 于2019年5月28日发布。特性包括:为所有应用代码进行差异化加载、针对惰性加载路由的动态导入、Web workers、支持 TypeScript 3.4,并且把 Angular Ivy 作为可选的预览特性。Angular Ivy 的可选预览特性包括:最值得期待的特性之一是 Ivy ,它是一个向后兼容的、基于增量式 DOM 架构的全新渲染引擎。Ivy 从设计之初就考虑到了摇树优化,这意味着应用的发布包中只会包含那些在应用中真正用到的 Angular 部件。可以预期,每一个版本都会向后兼容前一个版本。Google 承诺每年会进行两次升级。所有主版本都提供了 18 个月的支持。其中包括 6 个月的活跃支持,在此期间会定期发布更新和补丁。然后是12个月的长期支持(LTS),在此期间只会发布关键修复程序和安全补丁。
收起全文
  • 课程介绍: 初步了解和掌握angular的基础知识,熟练使用angular中的各类功能,并可以动手开发一个基于angular框架的应用系统。
  • 本课程是一个系列基础教程,目标是带领读者上手实战,课程以新版本 Angular 的 3 个核心概念作为主线:组件、路由、模块,加上业务开发过程中必须用到的特性:工具、指令、表单、RxJS、i18n、测试,一共分为 9 部分...

    课程介绍

    本课程是一个系列基础教程,目标是带领读者上手实战,课程以新版本 Angular 的 3 个核心概念作为主线:组件、路由、模块,加上业务开发过程中必须用到的特性:工具、指令、表单、RxJS、i18n、测试,一共分为 9 部分,34 篇文章。

    除了组件、路由、模块这 3 个核心小节具有很强的关联性之外,其它内容都是完全独立的,您可以在用到的时候再翻阅。

    认真读完这个系列文章之后,您会深入理解新版本 Angular 的概念模型,具备使用 Angular 上手进行开发的基本能力。

    课程内容

    Angular 初学者快速上手教程导读

    课程特色

    你可能会问:Angular 的文章到处有,网上一大片,我为什么要来读你这个系列文章?

    这是非常好的一个问题,说明你对阅读内容有质量要求。

    如果是我,我也会问这个问题。

    整体上说,这个系列的文章有以下特色:

    1. 我会按照初学者一般的学习过程,用我自己的语言一步一步进行讲解。如你所知,最近的5年我一直在玩前端方面的东西,从 jQuery、SVG、ExtJS、Adobe Flex、Angular,这样一路玩过来。尤其是2016年,这一整年的时间我都代表 Angular 项目组在中国进行技术推广。在这5年,我在超过40家企业、开源组织、大学里面进行了大量演讲,在网络上发布了大量的视频和文章。在到处交流的过程中,认识了很多人,有经验丰富的后端开发者,也有新入行的初学者,他们跟我讲过很多自己的困惑。所以,这个系列文章里面的内容我至少反复讲过20遍以上,我会把常见的一些疑问融入在内容里面。

    2. 我会帮你扫平日常开发中常见的坑,这些坑大部分都是开发者们反馈给我的,或者说到我这里吐槽过的。举几个典型的例子:

      • 很多开发者到我这里来抱怨说,在 Windows 平台上安装 @angular/cli 会报很多 error,那是因为 @angular/cli 在 Windows 平台上面依赖 Python 和Visual Studio 环境,而很多开发者的机器上并没有安装这些东西。
      • node-sass 模块被墙的问题,强烈推荐使用 cnpm 进行安装,可以非常有效地避免撞墙。
      • 一些开发者来抱怨说 @angular/cli 在打包的时候加上 --prod 参数会报错,无法编译。这是一个很常见的问题,因为 @angular/cli 最新的版本经常会有 bug,只要在你项目的 package.json 里面降低一个小版本号就OK。
      • @angular/cli 默认生成的 karma.conf.js 配置文件里面采用了一个有 bug 的 html 报告生成器,导致 ng test 运行报错,我们需要把这个 reporter 改成mocha(摩卡)。
      • 有一些朋友说,本地开发的时候运行得很好,上线之后所有请求404。这也是一个常见的坑,因为你需要给 Web 容器配置一下处理 http 请求的规则,把前端路由扔回去交给 Angular 处理,请参考这份文档

      诸如此类的坑还有不少,我都是一个坑一个坑踩过来的。当然,我相信你自己也能踩过来,但是从节约时间的角度看,还是跟着我的思路走一遍更快不是吗?

    3. 这个系列的文章全部聚焦使用层面的话题,覆盖日常开发中使用频最高的特性。除非迫不得已,尽量不扯原理。长期以来,我发现有很多朋友的学习方式存在误区。比如:有一些人上来就去研究“变更检测”的原理,还有 RxJS 的原理,这种方式除了打击你自己的自信心之外并不能得到任何好处。因为你迟早会发现,在计算机领域,任何东西研究到最底层都和“算法”、“数据结构”、“设计模式”有关。而就我所知,很多朋友并不具备研究这些内容的基础知识,不过是白白浪费自己的时间而已。所以,我推荐采用更加务实一点的方案,首先学会如何使用,等用熟了,有时间、有闲情的时候再去研究那些底层的原理。设计发动机很难,但是学会开车并不难,对吧?所以我写这个系列的目标很简单,就是带你学会开车,而不是教你设计发动机。

    4. 这个系列的文章非常看重“概念模型”( Mental Model )的构建。我发现,很多开发者已经做过非常多的项目,但是当你跟他聊的时候,你很快就会发现他并没有掌握这门框架的精髓。打几个比方,当别人提到 Spring 的时候,你的大脑里面第一个想到一定是 DI、IOC、AOP 这些东西;当别人提到 Hibernate 或者 Mybatis 的时候,你的大脑里面立即会浮现出 ORM 的概念;当别人提到 React 的时候,你想到的应该是 VDom、JSX;当别人提到 jQuery 的时候,你首先想到的应该是$对吧?所以,你可以看到,任何一个成功的框架都有自己独创的“概念模型”,或者叫“核心价值”也可以。这是框架本身存在的价值,也是你掌握这门框架应该紧扣的主线,而不是上来就陷入到茫茫多的技术细节里面去。

    5. 文章里面所涉及到例子总数量大约200个左右,有少量例子来自官方文档,其它都是我自己一点一点手动敲出来的。我把这些例子分成了9个开源项目,它们互相独立,方便大家进行参考和练习。这些教学用的开源项目本身是免费的,列在这篇文章的尾部。

    Angular 的概念模型

    既然如此,问题就来了,新版本的 Angular 的核心概念是什么呢?

    非常简单,一切都是围绕着“组件”( Component )的概念展开的:

    enter image description here

    • Component(组件)是整个框架的核心,也是终极目标。“组件化”的意义有2个:第一是分治,因为有了组件之后,我们可以把各种逻辑封装在组件内部,避免混在一起;第二是复用,封装成组件之后不仅可以在项目内部复用,而且可以沉淀下来跨项目复用。
    • NgModule(模块)是组织业务代码的利器,按照你自己的业务场景,把组件、服务、路由打包到模块里面,形成一个个的积木块,然后再用这些积木块来搭建出高楼大厦。
    • Router(路由)的角色也非常重要,它有3个重要的作用:第一是封装浏览器的 History 操作;第二是负责异步模块的加载;第三是管理组件的生命周期。

    所以,在这个系列的文章里面,Component、NgModule、Router 加起来会占据绝大部分篇幅,而一些琐碎的小特性会被忽略掉。我相信,你只要紧扣“组件化”这个主线,就能站在一个很高的角度统摄全局,从而掌握到这门框架的精髓。

    适合阅读的人群

    这个系列的文章适合以下人群阅读:

    • Angular 新版本的初学者
    • 有 AngularJS 1.x 经验的开发者
    • 希望了解 Angular 新版本核心特性的开发者

    特别注意:这个系列的文章不是前端入门读物,你至少需要会一门编程语言,无论前端还是后端都可以,如果你曾经使用过一门前端框架,那就更好了。

    集中回答一些常见的问题

    浏览器兼容性

    关于 Angular 的浏览器兼容性,请看下图:

    enter image description here

    有一些国内的开发者会来争论兼容 IE8 的问题,我想给你两个事实:

    • 第一个事实是:截至2017年7月底,Chrome 的全球市场份额已经接近60%,加上 Firefox的12.28%,真的没有那么多人用 IE 了。

    enter image description here

    数据来源

    • 第二个事实是:天猫已经于2016年4月宣布放弃支持 IE6、7、8。而根据百度流量研究院的统计,IE8目前的整体市场份额已经下降到了9.31%:

    enter image description here

    数据来源

    不值得为了这么少的市场份额付出那么多的研发和维护成本。

    你完全可以以上两点事实去说服你的客户。

    命名约定

    老版本使用 AngularJS 指代,所有新版本都叫做 Angular。原因很好理解,因为老版本是用 JS 开发的,所以带一个 JS 后缀,而新版本是基于 TypeScript 的,带 JS 后缀不合适。

    关于 TypeScript

    这个系列的文章不会单独讲 TypeScript,正如我一直强调的:TypeScript 不难,JavaScript 才难。你跟着我的思路,TypeScript 绝对不会成为你学习 Angular 的障碍。相反,一旦你写熟练了之后,TypeScript 可以非常有效地提升编码效率和程序可读性。

    关于版本号

    根据官方的解释,Angular 从2.0之后会保证向下兼容,每隔半年会升级一个大版本,只有升级大版本的时候才会做一些 breaking change。

    所以这个系列文章里面不再强调版本号,涉及到的所有实例代码都基于目前(2017-10)最新的4.x版本。

    内容列表

    这个系列文章一共分11章,34个小节。

    • 1 搭建开发环境
    • 2-1 组件概述
    • 2-2 把 CSS 预编译器改成 SASS
    • 2-3 模板
    • 2-4 组件间通讯
    • 2-5 生命周期钩子
    • 2-6 动效
    • 2-7 动态组件
    • 2-8 ShadowDOM
    • 2-9 内容投影
    • 2-10 @ContentChild@ContentChildren
    • 2-11 @ViewChild 与 @ViewChildren
    • 2-12 与 Polymer 封装组件的方式简单对比
    • 2-13 封装并发布你自己的组件库
    • 3-1 指令简介
    • 3-2 自定义指令
    • 3-3 直接在组件里面操作 DOM
    • 4 模块 @NgModule
    • 5-1 路由概述
    • 5-2 路由基本用法
    • 5-3 模块预加载
    • 5-4 路由守卫
    • 5-5 多重出口
    • 6-1 表单快速上手
    • 6-2 双向数据绑定
    • 6-3 表单校验
    • 6-4 模型驱动型表单
    • 6-5 动态表单
    • 7 服务
    • 8 RxJS 快速上手教程
    • 9 国际化
    • 10 自动化测试
    • 11 参考资源

    本系列课程对应的所有示例项目列表:

    1. https://gitee.com/mumu-osc/learn-component
    2. https://gitee.com/mumu-osc/learn-directive
    3. https://gitee.com/mumu-osc/learn-router
    4. https://gitee.com/mumu-osc/learn-module
    5. https://gitee.com/mumu-osc/learn-form
    6. https://gitee.com/mumu-osc/learn-service
    7. https://gitee.com/mumu-osc/learn-test
    8. https://gitee.com/mumu-osc/learn-webpack
    9. https://github.com/damoqiongqiu/angular-seo

    最后是那一句套话:水平有限,错漏难免,欢迎指正。可以在我的读者圈里跟我沟通交流。

    第1课:搭建开发环境

    NodeJS

    enter image description here

    2009年,NodeJS 发布了第一个版本,标志着前端开发正式告别了刀耕火种的原始状态,开始进入工业化时代。

    在 NodeJS 出现之前,前端开发领域有很多事情我们是做不到的,例如:

    • JS 代码的合并、压缩、混淆。
    • CSS 预处理。
    • 前端自动化测试。

    而这一切在 NodeJS 出现之后都得到了很好的解决:

    • 对 JS 代码的预处理经历了 Grunt、Gulp 的短暂辉煌之后,终于在 webpack 这里形成了事实标准的局面。
    • CSS 的预处理也从 LESS 发展到了 SASS。
    • 自动化测试一直是前端开发中的一个巨大痛点,由于前端在运行时严重依赖浏览器环境,导致我们一直无法像测试后端代码那样可以去编写测试用例。在有了 NodeJS 之后,我们终于有了 Karma+Jasmine 这样的单元测试组合,也有了基于 WebDriverJS 这样的可以和浏览器进行通讯的集成测试神器。

    就前端开发目前整体的状态来说,无论你使用什么框架,NodeJS、webpack、SASS、Karma+Jasmine、WebDriverJS 这个组合是无论如何绕不过去的。

    @angular/cli

    enter image description here

    在开发 Angular 应用的时候,当然也离不开大量基于 NodeJS 的工具,我们需要 TypeScript compiler、webpack、Karma、Jasmine、Protracter 等模块。

    有相关经验的开发者都知道,自己从头开始去搭建一套基于 webpack 的开发环境是一件非常麻烦的事情。很多初学者在搭建环境这一步上面消耗了过多的精力,导致学习热情受到了沉重的打击。

    当团队规模比较大的时候,在每个人的机器上配置环境需要消耗大量的时间。有一些团队为了避开这个坑,利用 Docker 来做开发环境的同步和版本升级,看起来也是一个非常不错的方案。

    Angular 项目组从一开始就注意到了这个问题,所以有了 @angular/cli 这个神器,它的底层基于 webpack,集成了以上提到的所有 NodeJS 组件。你只要装好 @angular/cli 就够了,而不需要自己从头一步一步安装那些 NodeJS 插件。

    当然,在安装 @angular/cli 之前你需要先把 NodeJS 安装好,请到官方网站下载安装包: https://nodejs.org/ ,安装过程和普通软件没有区别。装好 NodeJS 之后就可以安装 @angular/cli 了,由于 npm 会自动访问海外的服务器,所以强烈推荐使用 cnpm 进行安装:

    npm i -g cnpm --registry=https://registry.npm.taobao.orgcnpm i -g @angular/cli

    cnpm 是淘宝发布的一款工具,会自动把 npm 上面的所有包定时同步到国内的服务器上来,cnpm 本身也是一款 NodeJS 模块。

    @angular/cli 安装成功之后你的终端里面将会多出一个名叫 ng 的命令,敲下 ng,将会显示完整的帮助文档:

    enter image description here

    创建第一个项目

    我们来创建第一个入门项目 HelloAngular,请在你的终端里面运行:

    ng new HelloAngular

    @angular/cli 将会自动帮你把目录结构创建好,并且会自动生成一些模板化的文件,就像这样:

    enter image description here

    请特别注意:@angular/cli 在自动生成好项目骨架之后,会立即自动使用 npm 来安装所依赖的 Node 模块,所以这里我们要 Ctrl+C 终止掉,然后自己进入项目的根目录,使用 cnpm 来进行安装。

    enter image description here

    安装完成之后,使用 ng serve 命令启动项目:

    enter image description here

    打开你的浏览器,访问默认的4200端口,看到以下界面说明环境 OK 了:

    enter image description here

    请注意:

    • 这里是 serve,不是 server,我看到一些初学者经常坑在这个地方。
    • 如果你需要修改端口号,可以用 ng serve --port ****来进行指定。
    • 如果你想让编译的包更小一些,可以使用 ng serve --prod,@angular/cli 会启用 TreeShaking 特性,加了参数之后编译的过程也会慢很多。所以,在正常的开发过程里面请不要加 --prod 参数。
    • ng serve 是在内存里面生成项目,如果你想看到项目编译之后的产物,请运行 ng build。构建最终产品版本可以加参数,ng build --prod。

    ng 提供了很多非常好用的工具,除了可以利用 ng new 来自动创建项目骨架之外,它还可以帮助我们创建 Angular 里面所涉及到的很多模块,最常用的几个如下:

    • 自动创建组件:ng generate component MyComponent,可以简写成 ng g c MyComponent。创建组件的时候也可以带路径,比如:ng generate component mydir/MyComponent
    • 自动创建指令:ng g d MyDirective
    • 自动创建服务:ng g s MyService
    • 构建项目:ng build,如果你想构建最终的产品版本,可以用 ng build --prod

    更多的命令和参数请在终端里面敲 ng 仔细查看,尽快熟悉这些工具可以非常显著地提升你的编码效率。

    一些常见的坑

    @angular/cli 这种“全家桶”式的设计带来了很大的方便,同时也有一些人不太喜欢,因为很多底层的东西被屏蔽掉了,开发者不能天马行空地自由发挥。比如:@angular/cli 把底层 webpack 的配置文件屏蔽掉了,很多喜欢自己手动配 webpack 的开发者就感到很不爽。

    对于国内的开发者来说,上面这些其实不是最重要的,国内开发者碰到的坑主要是由两点引起的:

    1. 第一点是网络问题:比如 node-sass 这个模块你很有可能就装不上,原因你懂的。
    2. 第二点是开发环境导致的问题:国内使用 Windows 平台的开发者比例依然巨大,而 @angular/cli 在 Windows 平台上有一些非常恶心的依赖,比如它需要依赖 python 环境、Visual Studio 环境。

    所以,如果你的开发平台是 Windows,请特别注意:

    1. 如果你知道如何给 npm 配置代理,也知道如何翻墙,请首选 npm 来安装 @angular/cli。
    2. 否则,请使用 cnpm 来安装 @angular/cli,原因有三:1、cnpm 的缓存服务器在国内,你装东西的速度会快很多;2、用 cnpm 可以帮你避开某些模块装不上的问题,因为它在服务器上面做了缓存;3、cnpm 还把一些包都预编译好了缓存在服务端,不需要把源码下载到你本地去编译,所以你的机器上可以没有那一大堆麻烦的环境。
    3. 如果安装失败,请手动把 node_modules 目录删掉重试一遍,全局的@angular/cli 也需要删掉重装,cnpm uninstall -g @angular/cli。
    4. 如果 node_modules 删不掉,爆出路径过长之类的错误,请尝试用一些文件粉碎机之类的工具强行删除。
    5. 最新版本的 @angular/cli 经常会有 bug,尤其是在 Windows 平台上面,所以请不要追新版本追太紧。如果你发现了莫名其妙的问题,请尝试降低一个主版本试试。这一点非常重要,很多初学者会非常困惑,代码什么都没改,就升级了一下环境,然后就各种编译报错。
    6. 对于 Mac 用户或者 *nix 用户,请特别注意权限问题,命令前面最好加上 sudo,保证有 root 权限。
    7. 无论你用什么开发环境,安装的过程中请仔细看 log。很多朋友没有看 log 的习惯,报错的时候直接懵掉,根本不知道发生了什么。

    VS Code

    enter image description here

    如你所知,一直以来,前端开发领域并没有一款特别好用的开发和调试工具。

    • WebStorm 很强大,但是吃资源很严重。
    • Sublime Text 插件很多,可惜要收费,而国内的企业还没有养成花钱购买开发工具的习惯。
    • Chrome 的开发者工具很好用,但是要直接调试 TypeScript 很麻烦。

    所以,Visual Studio Code(简称 VS Code)才会呈现出爆炸性增长的趋势。它是微软开发的一款前端编辑器,完全开源免费。VS Code 底层是 Electron,界面本身是用 TypeScript 开发的。对于 Angular 开发者来说,当然要强烈推荐 VS Code。最值得一提的是,从1.14开始,可以直接在 VS Code 里面调试 TypeScript 代码。

    第一步:环境配置

    • 确保你的 Chrome 安装在默认位置。
    • 确保你的 VS Code 里面安装了 Debugger for Chrome 这个插件。
    • 把 @angular/cli 安装到全局空间 npm install -g @angular/cli,国内用户请使用 cnpm 进行安装。注意,你最好升级到最新版本的 @angular/cli,避免版本兼容问题。
    • 用 @angular/cli 创建新项目 ng new my-app,本来就已经用 @angular/cli 创建的项目请忽略这一步,继续往下走,因为只要是 cli 创建的项目,后面的步骤都是有效的。
    • 用 VS Code 打开项目,进入项目根目录

    第二步:配置 launch.json

    enter image description here

    请参照以上步骤打开 launch.json 配置文件。

    enter image description here

    请把你本地 launch.json 文件里面的内容改成这样:

    {    "version": "0.2.0",    "configurations": [        {            "type": "chrome",            "request": "launch",            "name": "Chrome",            "url": "http://localhost:4200",            "webRoot": "${workspaceRoot}"        }    ]}

    第三步:开始 Debug

    在你的 app.component.ts 的构造函数里面打个断点,我本地是这样打断点的:

    enter image description here

    打开终端,进入项目根目录,运行 ng serve 启动项目,然后从 VS Code 的 debug 界面启动 Chrome

    enter image description here

    注意,你可能需要 F5 刷新一下 Chrome 才能进入断点!

    enter image description here

    小结

    目前,无论你使用什么前端框架,都必然要使用到各种 NodeJS 工具,Angular 也不例外。与其它框架不同,Angular 从一开始就走的“全家桶”式的设计思路,因此 @angular/cli 这款工具里面集成了日常开发需要使用的所有 Node 模块,使用 @angular/cli 可以大幅度降低搭建开发环境的难度。

    第2-1课:组件:概述

    enter image description here

    几乎所有前端框架都在玩“组件化”,而且最近都不约而同地选择了“标签化”这种思路,Angular 也不例外。

    对新版本的 Angular 来说,一切都是围绕着“组件化”展开的,组件是 Angular 的核心概念模型。

    以下是一个最简单的 Angular 组件定义:

    enter image description here

    • @Component:这是一个 Decorator(装饰器),其作用类似于 Java 里面的注解。Decorator 这个语言特性目前(2017-10)处于 Stage 2(草稿)状态,还不是 ECMA 的正式规范。
    • selector:组件的标签名,外部使用者可以这样来使用这个组件:<app-root>。默认情况下,ng 命令生成出来的组件都会带上一个 app 前缀,如果你不喜欢,可以在 angular-cli.json 里面修改 prefix 配置项,设置为空字符串将会不带任何前缀。
    • templateUrl:引用外部的 HTML 模板。如果你想直接编写内联模板,可以使用 template,支持 ES6 引入的“模板字符串”写法
    • styleUrls:引用外部 CSS 样式文件,这是一个数组,也就意味着可以引用多份 CSS 文件。
    • export class AppComponent:这是 ES6 里面引入的模块和 class 定义方式。

    本节完整的实例代码请参见这里

    第2-2课:组件:把 CSS 预编译器改成 SASS

    enter image description here

    SASS 是一款非常好用的 CSS 预编译器,Bootstrap 官方从4.0开始已经切换到了 SASS。

    目前(2017-10),@angular/cli 创建项目的时候没有自动使用 SASS 作为预编译器,我们需要自己手动修改一些配置文件,请按照以下步骤依次修改:

    • angular-cli.json 里面的 styles.css 后缀改成 .scssenter image description here当你后面再使用 ng g c *** 自动创建组件的时候,默认就会生成 .scss 后缀的样式文件了。

    • angular-cli.json 里面的 styleExt 改成 .scssenter image description here

    • src 下面 style.css 改成 style.scssenter image description here

    • app.component.scssenter image description here

    • app.component.ts 里面对应修改enter image description here

    改完之后,重新 ng serve,打开浏览器查看效果。

    小结

    本节完整的实例代码请参见这里

    SASS 的 API 请参考官方网站

    SASS 只是一个预编译器,它支持所有 CSS 原生语法。利用 SASS 可以提升你的 CSS 编码效率,增强 CSS 代码的可维护性,但是千万不要幻想从此就可以不用学习 CSS 基础知识了。

    第2-3课:组件:模板

    enter image description here

    模板是编写 Angular 组件最重要的一环,你至少需要深入理解以下知识点才能玩转 Angular 模板:

    1. 对比各种 JS 模板引擎的设计思路
    2. Mustache(八字胡)语法
    3. 模板内的局部变量
    4. 属性绑定、事件绑定、双向绑定
    5. 在模板里面使用结构型指令 *ngIf、*ngFor、ngSwitch
    6. 在模板里面使用属性型指令 NgClass、NgStyle、NgModel
    7. 在模板里面使用管道格式化数据

    对比各种 JS 模板引擎的设计思路

    几乎每一款前端框架都会提供自己的模板语法,在 jQuery 如日中天的时代,有 Handlebars 那种功能超强的模板。最近有 React 推崇的 JSX 模板写法,当然还有 Angular 提供的那种与“指令”紧密结合的模板语法。

    综合来说,无论是哪一种前端模板,大家都比较推崇“轻逻辑”( logic-less )的设计思路。

    何为“轻逻辑”?

    简而言之,所谓“轻逻辑”就是说,你不能在模板里面编写非常复杂的 JavaScript 表达式。比如,Angular 的模板语法就有规定:

    • 你不能在模板里面 new 对象
    • 不能使用=、+=、-=这类的表达式
    • 不能用++、--运算符
    • 不能使用位运算符

    为什么要“轻逻辑”?

    有一个非常重要的原因,比如你编写了以下 Angular 模板:

    <ul>    <li *ngFor="let race of races">        {{race.name}}    </li></ul>

    很明显,浏览器不认识 *ngFor 和 {{...}} 这种语法,所以必须在浏览器里面进行“编译”,获得对应的模板函数,然后再把数据传递给模板函数,最终结合起来获得一堆 HTML 标签,然后才能把这一堆标签插入到 DOM 树里面去。

    如果启用了 AOT,处理的步骤有一些变化,@angular/cli 会对模板进行“静态编译”,避免在浏览器里面动态编译的过程。

    而 Handlebars 这种模板引擎完全是运行时编译模板字符串的,你可以编写以下代码:

    //定义模板字符串var source=`<ul>    {{#each races}}        <li>{{name}}</li>    {{/each}}</ul>`;//在运行时把模板字符串编译成JS函数var templateFn=Handlebars.compile(source);//把数据传给模板函数,获得最终的HTMLvar html=templateFn([    {name:'人族'},    {name:'神族'},    {name:'虫族'}]);

    注意到 Handlebars.compile 这个调用了吧?这个地方的本质是在运行时把模板字符串“编译”成了一个 JS 函数。

    鉴于 JS 解释执行的特性,你可能会担忧这里会有性能问题。这种担忧是合理的,但是 Handlebars 是一款非常优秀的模板引擎,它在内部做了各种优化和缓存处理。模板字符串一般只会在第一次被调用的时候编译一次,Handlebars 会把编译好的函数缓存起来,后面再次调用的时候会从缓存里面获取,而不会多次进行“编译”。

    上面我们多次提到了“编译”这个词,所以很显然这里有一个东西是无法避免的,那就是我们必须提供一个 JS 版的“编译器”,让这个“编译器”运行在浏览器里面,这样才能在运行时把用户编写的模板字符串“编译”成模板函数。

    有一些模板引擎会真的去用 JS 编写一款“编译器”出来,比如 Angular 和 Handlebars,它们都真的编写了一款 JS( TS )版的编译器。而有一些简单的模板引擎只是用正则表达式做了字符串替换而已,显得特别简陋。这种简陋的模板引擎对模板的写法有非常多的限制,因为它不是真正的编译器,能支持的语法特性非常有限。

    所以,评估一款模板引擎的强弱,最核心的东西就是评估它的“编译器”做得怎么样。但是不管怎么说,毕竟是 JS 版的“编译器”,我们不可能把它做得像 g++ 那么强大,也没有必要做得那么强大,因为这个 JS 版的编译器需要在浏览器里面运行,搞得太复杂浏览器拖不动!

    以上就是为什么大多数模板引擎都要强调“轻逻辑”的最根本原因。

    对于 Angular 来说,强调“轻逻辑”还有另一个原因:在组件的整个生命周期里面,模板函数会被执行很多次。你可以想象, Angular 每次要刷新组件的外观的时候,都需要去调用一下模板函数,如果你在模板里面编写了非常复杂的代码,一定会增加渲染时间,用户一定会感到界面有“卡顿”。

    人眼的视觉延迟大约是100ms到400ms之间,如果整个页面的渲染时间超过400ms,界面基本上就卡得没法用了。有一些做游戏的开发者会追求60fps刷新率的细腻感觉,60分之1秒约等于16.7ms,如果 UI 整体的渲染时间超过了16.7ms,就没法达到这个要求了。

    轻逻辑( logic-less )带来了效率的提升,也带来了一些不方便,比如很多模板引擎都实现了 if 语句,但是没有实现 else,所以开发者们在编写复杂业务逻辑的时候模板代码会显得非常啰嗦。

    目前来说,并没有完美的方案能同时兼顾运行效率和语法表现能力,这里只能取一个平衡。

    Mustache 语法

    Mustache 语法也就是你们说的双花括号语法{{...}},老外觉得它像八字胡子,很奇怪啊,难道老外喜欢侧着头看东西?

    好消息是,很多模板引擎都接受了 Mustache 语法,这样一来学习量又降低了不少,开心吧?

    关于 Mustache 语法,你需要掌握3点:

    1. 它可以获取到组件里面定义的属性值。
    2. 它可以自动计算简单的数学表达式,例如:加减乘除、取模。
    3. 它可以获得方法的返回值。

    请依次看例子:

    插值语法关键代码实例:

    <h3>    欢迎来到{{title}}!</h3>
    public title = '假的星际争霸2'; 

    简单的数学表达式求值:

    <h3>1+1={{1+1}}</h3>

    调用组件里面定义的方法:

    <h3>可以调用方法{{getVal()}}</h3>
    public getVal():any{    return 65535;}

    模板内的局部变量

    <input #heroInput><p>{{heroInput.value}}</p>

    有一些朋友会追问,如果我在模板里面定义的局部变量和组件内部的属性重名会怎么样呢?

    如果真的出现了重名,Angular 会按照以下优先级来进行处理:

    模板局部变量 > 指令中的同名变量 > 组件中的同名属性。

    这种优先级规则和 JSP 里面的变量取值规则非常类似,对比一下很好理解对不对?你可以自己写代码测试一下。

    属性绑定

    属性绑定是用方括号来做的,写法:

    <img [src]="imgSrc" />
    public imgSrc:string="./assets/imgs/1.jpg";

    很明显,这种绑定是单向的。

    事件绑定

    事件绑定是用圆括号来做的,写法:

    <button class="btn btn-success" (click)="btnClick($event)">测试事件</button>

    对应 Component 内部的方法定义:

    public btnClick(event):void{    alert("测试事件绑定!");}

    双向绑定

    双向绑定是通过方括号里面套一个圆括号来做的,模板写法:

    <font-resizer [(size)]="fontSizePx"></font-resizer>

    对应组件内部的属性定义:

    public fontSizePx:number=14;

    AngularJS 是第一个把“双向数据绑定”这个特性带到前端来的框架,这也是 AngularJS 当年最受开发者追捧的特性,之一。

    根据 AngularJS 团队当年讲的故事,“双向数据绑定”这个特性可以大幅度压缩前端代码的规模。大家可以回想一下 jQuery 时代的做法,如果要实现类似的效果,是不是要自己去编写大量的代码?尤其是那种大规模的表单,一大堆的赋值和取值操作,都是非常丑陋的“面条”代码,而有了“双向数据绑定”特性之后,一个绑定表达式就搞定。

    目前,主流的几款前端框架都已经接受了“双向数据绑定”这个特性。

    当然,也有一些人不喜欢“双向数据绑定”,还有人专门写了文章来进行批判,也算是前端一景。

    在模板里面使用结构型指令

    Angular 有3个内置的结构型指令:*ngIf、*ngFor、ngSwitch。ngSwitch 的语法比较啰嗦,使用频率小一些。

    *ngIf 代码实例:

    <p *ngIf="isShow" style="background-color:#ff3300">显示还是不显示?</p><button class="btn btn-success" (click)="toggleShow()">控制显示隐藏</button>
    public isShow:boolean=true;public toggleShow():void{    this.isShow=!this.isShow;}

    *ngFor 代码实例:

    <li *ngFor="let race of races;let i=index;">    {{i+1}}-{{race.name}}</li>
    public races:Array<any>=[    {name:"人族"},    {name:"虫族"},    {name:"神族"}];

    *ngSwitch 代码实例:

    <div [ngSwitch]="mapStatus">    <p *ngSwitchCase="0">下载中...</p>    <p *ngSwitchCase="1">正在读取...</p>    <p *ngSwitchDefault>系统繁忙...</p></div>
    public mapStatus:number=1;

    特别注意:一个 HTML 标签上只能同时使用一个结构型的指令。

    因为“结构型”指令会修改 DOM 结构,如果在一个标签上使用多个结构型指令,大家都一起去修改 DOM 结构,到时候到底谁说了算?

    那么需要在同一个 HTML 上使用多个结构型指令应该怎么办呢?有两个办法:

    • 加一层空的 div 标签
    • 加一层<ng-container>

    在模板里面使用属性型指令

    使用频率比较高的3个内置指令是:NgClass、NgStyle、NgModel。

    NgClass 使用案例代码:

    <div [ngClass]="currentClasses">同时批量设置多个样式</div><button class="btn btn-success" (click)="setCurrentClasses()">设置</button>
    public currentClasses: {};public canSave: boolean = true;public isUnchanged: boolean = true;public isSpecial: boolean = true;setCurrentClasses() {    this.currentClasses = {        'saveable': this.canSave,        'modified': this.isUnchanged,        'special': this.isSpecial    };}
    .saveable{    font-size: 18px;} .modified {    font-weight: bold;}.special{    background-color: #ff3300;}

    NgStyle 使用案例代码:

    <div [ngStyle]="currentStyles">    用NgStyle批量修改内联样式!</div><button class="btn btn-success" (click)="setCurrentStyles()">设置</button>
    public currentStyles: {}public canSave:boolean=false;public isUnchanged:boolean=false;public isSpecial:boolean=false;setCurrentStyles() {    this.currentStyles = {        'font-style':  this.canSave      ? 'italic' : 'normal',        'font-weight': !this.isUnchanged ? 'bold'   : 'normal',        'font-size':   this.isSpecial    ? '36px'   : '12px'    };}

    ngStyle 这种方式相当于在代码里面写 CSS 样式,比较丑陋,违反了注意点分离的原则,而且将来不太好修改,非常不建议这样写。

    NgModel 使用案例代码:

    <p class="text-danger">ngModel只能用在表单类的元素上面</p>    <input [(ngModel)]="currentRace.name"><p>{{currentRace.name}}</p>
    public currentRace:any={name:"随机种族"};

    请注意,如果你需要使用 NgModel 来进行双向数据绑定,必须要在对应的模块里面 import FormsModule。

    管道

    管道的一个典型作用是用来格式化数据,来一个最简单的例子:

    {{currentTime | date:'yyyy-MM-dd HH:mm:ss'}}
    public currentTime: Date = new Date();

    Angular里面一共内置了12个管道:

    enter image description here

    在复杂的业务场景里面,12个管道肯定不够用,如果需要自定义管道,请查看这里的例子

    管道还有另一个典型的作用,就是用来做国际化,后面有一个独立的小节专门演示 Angular 的国际化写法。

    小结

    本节完整可运行的实例代码请参见这里请检出 template 分支。

    第2-4课:组件:组件间通讯
    第2-5课:组件:生命周期钩子
    第2-6课:组件:动效
    第2-7课:组件:动态组件
    第2-8课: 组件:ShadowDOM
    第2-9课:组件:内容投影
    第2-10课:组件:@ContentChild 和 @ContentChildren
    第2-11课:组件:@ViewChild 与 @ViewChildren
    第2-12课:与 Polymer 封装组件的方式简单对比
    第2-13课:封装并发布你自己的组件库
    第3-1课:指令
    第3-2课:自定义指令
    第3-3课:在组件里面直接操作DOM
    第4课:模块 @NgModule
    第5-1课:路由:概述
    第5-2课:路由:基本用法
    第5-3课:路由:模块预加载
    第5-4课: 路由:路由守卫
    第5-5课:路由:多重出口
    第6-1课:表单:快速上手
    第6-2课: 表单:双向数据绑定
    第6-3课:表单:表单校验
    第6-4课:表单:模型驱动型表单
    第6-5课:表单:动态表单
    第7课:服务
    第8课: RxJS 快速上手教程
    第9课:国际化
    第10课:前端自动化测试
    第11课:参考资源

    阅读全文: http://gitbook.cn/gitchat/column/59dae2081e6d652a5a9c3603

    展开全文
  • 本篇课程结合前面学习的Angular6和Django框架,将两个框架通过一个实战项目结合在一起,用目前流行的前后端分离开发模式,从零起步,一步步开发成为一个完整的项目并最终打包发布。视频中所出现的细节,错误,以及...
  • 本课程是Angular 6 的案例实战篇,在本课中,通过4章12小节详细说明,以案例实战的方式,介绍如何使用angular开发一个电影信息查看功能的过程,整个课程以知识点为基础,以案例为主线,通过案例夯实知识点,章节层层...
  • Angular——浅知

    2019-08-11 15:08:16
      “Angular”很多人都知道前端很火的框架,有很多的优点,此次参与的项目前端也使用的angular,所以最近正在学习中。下面就简单介绍一下angular,以及开发angular程序前要做的准备工作! **简介** 1.是什么?...

      “Angular”很多人都知道前端很火的框架,有很多的优点,此次参与的项目前端也使用的angular,所以最近正在学习中。下面就简单介绍一下angular,以及开发angular程序前要做的准备工作!

    *简介

    1.是什么?
      Angular 是一个开发平台。它能帮你更轻松的构建 Web 应用。Angular 集声明式模板、依赖注入、端到端工具和一些最佳实践于一身,为你解决开发方面的各种挑战。Angular 为开发者提升构建 Web、手机或桌面应用的能力。

    2.架构
      首先付一张在视频中看到的关于angular程序架构图,然后对angular程序架构有个大概了解。
    这里写图片描述
      大的架构:用户user和应用APP作交互,angular本身是一个客户端框架,开发出来的都是客户端程序,客户端程序需要与服务器做交互,从服务器获取数据传递数据,


      ◇◇app应用:angular的应用至少包含一个模块NgModule和一个组件component(PS:组件之间可以有父子关系,组件可以调用服务,服务也可以调服务,就是服务之间也可以互相调用)
      ◇◇指令:也是angular的重要组成部分,允许你向HTML元素添加自定义行为,比如可以写一个自动完成的指令,把这个指令写到input标签上,这个标签就会有自动完成的功能,angular框架内置了大量的指令来帮助我们解决日常开发的问题

      ◇◇模块:可以把指令、组件、服务看成积木中的小块,模块是一个一个的塑料袋,这些小块可以组成一个小汽车,把这些小块放进一个袋子里,那些小块可以组成一个轮船放在另外一个袋子里


    3.使用——职责
      组件、服务、指令是用来完成功能的,模块是用来打包分发这些功能的
      对于程序来说,如果四个组件、两个服务、加上某个指令能放在一起可以提供一个功能,如登录功能,就会把这些组件服务指令放在登录模块里。如果开发下一个程序也需要登录,可以把登录模块引入这个项目中即可

    *Angular目录结构

    1、浅层目录结构

    e2e:端到端的测试目录,用于自动测试


    node-modules:存放第三方依赖包


    src:应用程序源码目录


    angular-cli.json:angular命令行工具的配置文件,如果额外引了第三方依赖包,配置文件会被修改


    karma.conf.js:karma是单元测试的执行器,karma.conf.js是karma的配置文件


    package.json:标准的npm工具的配置文件,文件里列出了该应用程序所使用的第三方依赖包


    protractor.conf.js:自动测试的配置文件


    README.md:说明文件


    tslint.joso:tslint的配置文件,用于定义typescript

    2、深层src目录

    app:应用的组件和模块


    assets:静态资源目录,可以存放图片等


    environments:环境配置(如:开发环境、测试环境、生产环境)


    index.html:整个应用的根HTML,是程序启动访问的页面


    main.ts:整个项目的入口点,angular通过这个启动项目


    *Angular应用启动

      嘿嘿,小菜要抛问题了!刚接触angular时,有没有疑惑编写完应用程序如何启动呢?启动时加载哪个页面?加载哪些脚本?脚本又需要做什么事呢?


    ◆启动加载的页面
      默认情况下src下的index.html是angular应用时启动加载的页面
    ◆启动加载的脚本
      src下的main.ts文件是angular应用时启动加载的脚本,负责引导angular应用启动

    *Angular与jquery的比较

    ◇jquery
      jquery需要操作页面上的道路,假如要显示一个业务卡片时,首先需要拿到这一列卡片外边的一个父节点的dom节点,然后生成html插入到里面去,这是在操作页面元素
    ◇Angular
      在angular中:则不需要做dom操作,需要做的就是在后台声明一些包含数据的属性,然后把模版和数据绑定起来,然后根据你的数据变化来呈现相应的页面

    展开全文
  • Angular框架入门

    2018-11-03 14:36:58
    1.AngularJS简介  AngularJS诞生于2009年,由Misko Hevery 等人创建,后为Google所收购。是一款优秀的前端JS框架,已经被用于Google的多款产品当中。AngularJS有着诸多特性,最为核心的是:MVC、模块化、自动化...

     

    1.AngularJS简介


        AngularJS诞生于2009年,由Misko Hevery 等人创建,后为Google所收购。是一款优秀的前端JS框架,已经被用于Google的多款产品当中。AngularJS有着诸多特性,最为核心的是:MVC、模块化、自动化双向数据绑定、依赖注入等等。


    下载地址:https://code.angularjs.org/

    学习版本:angular-1.6.9.zip(2018-02-02)

    2.AngularJS四大特征

    2.1 MVC模式


        Angular遵循软件工程的MVC模式,并鼓励展现,数据,和逻辑组件之间的松耦合.通过依赖注入(dependency injection),Angular为客户端的Web应用带来了传统服务端的服务,例如独立于视图的控制。 因此,后端减少了许多负担,产生了更轻的Web应用。

    Model:数据,其实就是angular变量($scope.XX);

    View: 数据的呈现,Html+Directive(指令);

    Controller:操作数据,就是function,数据的增删改查;

    2.2 双向绑定

        AngularJS是建立在这样的信念上的:即声明式编程应该用于构建用户界面以及编写软件构建,而指令式编程非常适合来表示业务逻辑。框架采用并扩展了传统HTML,通过双向的数据绑定来适应动态内容,双向的数据绑定允许模型和视图之间的自动同步。因此,AngularJS使得对DOM的操作不再重要并提升了可测试性。

    2.3依赖注入


        依赖注入(Dependency Injection,简称DI)是一种设计模式, 指某个对象依赖的其他对象无需手工创建,只需要“吼一嗓子”,则此对象在创建时,其依赖的对象由框架来自动创建并注入进来,其实就是最少知识法则;模块中所有的service和provider两类对象,都可以根据形参名称实现DI.


    2.4 模块化设计

       高内聚低耦合法则:

          1)官方提供的模块  ng、ngRoute、ngAnimate

          2)用户自定义的模块 angular.module('模块名',[ ])


    3 基础指令


    3.0 导包   

    <script src="js/angular.min.js"></script>

    3.1 表达式

    语法格式:{{变量名}}     或者       {{对象.变量名}}

    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    <script src="angular.min.js"></script>
    </head>
    <body>
      <div ng-app>
      {{100 + 100}}
      </div>
    </body>
    </html>

    结果:

    ng-app 指令定义了 Angular应用的根元素,在根元素的所有子元素中用到指令,angular会自动识别。

    ng-app 指令在网页加载完毕时会自动初始化应用中的angular的指令。

    3.2 双向绑定

    语法格式:ng-model=”变量名”   或者 ng-model=”对象.变量名”

    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    <script src="angular.min.js"></script>
    </head>
    <body>
      <div ng-app>
       name:<input type="text" ng-model="name" /></br>
       sex:<input type="text" ng-model="user.sex" /></br>
       age: <input type="text" ng-model="user.age" /></br>
       name:{{name}} <br>
       sex: {{user.sex}} <br>
       age: {{user.age}} <br>
      </div>
    </body>
    </html>

    结果:

    说明:ng-model 指令用于绑定变量,这样用户在文本框输入的内容会绑定到变量上,而表达式可以实时地输出变量。

    3.3 初始化指令

    语法格式:ng-init=”变量名=’变量值’;   变量名=’变量值’”

    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    <script src="angular.min.js"></script>
    </head>
    <body>
      <div ng-app ng-init ="name='xiaoming';user.sex='man';user.age=10 ">
       name:<input type="text" ng-model="name" /></br>
       sex:<input type="text" ng-model="user.sex" /></br>
       age: <input type="text" ng-model="user.age" /></br>
       name:{{name}} <br>
       sex: {{user.sex}} <br>
       age: {{user.age}} <br>
      </div>
    </body>
    </html>

    结果:

    3.4 控制器

    定义模块语法格式:var 变量名 = angular.module(“模块名”, []);

    []为数组对象,可以添加其他模块

    定义控制器语法格式:

    模块变量名.controller(“控制器名”, function($scope){});

    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    <script src="angular.min.js"></script>
    <script type="text/javascript">
        /*定义myApp模块*/
          var app = angular.module("myApp",[]);
    	/*将myAPP模块添加控制器*/
    	   app.controller("myController",function($scope){
    	     $scope.add = function(){
    		  return parseInt($scope.x)+parseInt($scope.y);
    		 };
    	   });
    </script>
    </head>
    <body>
      <div ng-app ="myApp" ng-controller="myController">
       x:<input type="text" ng-model="x" /></br>
       y:<input type="text" ng-model="y" /></br>
       结果:{{add()}} <br>
      </div>
    </body>
    </html>

    结果:

    ng-controller指定所使用的控制器。

    理解 $scope作用域:

    $scope 贯穿整个 Angular App应用,它与数据模型相关联,同时也是表达式执行的上下文.有了$scope相当于在视图和控制器之间建立了一个通道,基于作用域视图在修改数据时会立刻更新 $scope,同样的$scope 发生改变时也会立刻重新渲染视图。

    注意:mg-model绑定的变量数据都存放在$scope作用域对象中。

    3.5 事件指令

    l ng-click:单击事件

    l ng-dblclick:双击事件

    l ng-blur:失去焦点事件

    l ng-focus:获取焦点事件

    l ng-change:对应onchange改变事件

    l ng-keydown:键盘按键按下事件

    l ng-keyup:键盘按键按下并松开

    l ng-keypress:同上

    l ng-mousedown:鼠标按下事件

    l ng-mouseup:鼠标按下弹起

    l ng-mouseenter:鼠标进入事件

    l ng-mouseleave:鼠标离开事件

    l ng-mousemove:鼠标移动事件

    l ng-mouseover:鼠标进入事件


    语法格式:ng-xxx=”控制器中定义的方法名();”;
     

    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    <script src="angular.min.js"></script>
    <script type="text/javascript">
        /*定义myApp模块*/
          var app = angular.module("myApp",[]);
    	/*将myAPP模块添加控制器*/
    	   app.controller("myController",function($scope){
    	     $scope.blur = function(){
    		  alert($scope.x);
    		 };
    		 $scope.keyup = function(){
    		  alert($scope.y);
    		 };
    	     $scope.add = function(){
    		     $scope.count =parseInt($scope.x)+parseInt($scope.y);
    			 };
    			 
    		 });
    </script>
    </head>
    <body>
      <div ng-app ="myApp" ng-controller="myController">
       x:<input type="text" ng-model="x" ng-blur="blur()"/></br>
       y:<input type="text" ng-model="y" ng-keyup="keyup()"/></br>
         <input type="button" value="计算" ng-click="add()" /> <br>
       结果:{{count}} <br>
      </div>
    </body>
    </html>

    结果:

    说明:ng-xxx事件指令,绑定控制器的某个方法。

     

    3.6 循环数组

    语法格式:ng-repeat=”变量名 in 集合或数组”;

    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    <script src="angular.min.js"></script>
    <script type="text/javascript">
        /*定义myApp模块*/
          var app = angular.module("myApp",[]);
    	/*将myAPP模块添加控制器*/
    	  app.controller("myController",function($scope){
    	       /*定义数组*/
    			$scope.list = [10,20,30,40,50];
    		 });
    </script>
    </head>
    <body>
      <div ng-app ="myApp" ng-controller="myController">
         <ul ng-repeat="m in list">
    	  <li>{{m}}</li>
    	 </ul>
      </div>
    </body>
    </html>

    结果:

    3.7 循环对象数组

    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    <script src="angular.min.js"></script>
    <script type="text/javascript">
        /*定义myApp模块*/
          var app = angular.module("myApp",[]);
    	/*将myAPP模块添加控制器*/
    	  app.controller("myController",function($scope){
    	       /*定义数组对象*/
    			$scope.list = [{name:"xiaoming",sex:"男",age:10},
    						{name:"sdfs",sex:"女",age:20},
    						{name:"sfg",sex:"man",age:24}];
    		 });
    </script>
    </head>
    <body>
      <div ng-app ="myApp" ng-controller="myController">
         <table>
    	 <tr>
    	   <th>id</th>
    	   <th>name</th>
    	   <th>sex</th>
    	   <th>age</th>
    	 </tr>
    	 <tr ng-repeat = "m in list">
    	  <td>{{$index+1}}</td>
    	  <td>{{m.name}}</td>
    	  <td>{{m.sex}}</td>
    	  <td>{{m.age}}</td>
    	 </tr>
    	 </table>
      </div>
    </body>
    </html>

    结果:

    $index:获取迭代时的索引号。

     

    3.8 条件指令

    语法格式:ng-if=”条件表达式”;

    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    <script src="angular.min.js"></script>
    <script type="text/javascript">
        /*定义myApp模块*/
          var app = angular.module("myApp",[]);
    	/*将myAPP模块添加控制器*/
    	  app.controller("myController",function($scope){
    	       /*定义对象*/
    			$scope.a ={age:22} ;
    		 });
    </script>
    </head>
    <body>
      <div ng-app ="myApp" ng-controller="myController">
        <h1 ng-if="a.age>20">{{a.age}}</h1>
      </div>
    </body>
    </html>

    结果:

    3.9 复选框

    l ng-true-value="true": 选中值

    l ng-false-value="false": 未选中值

    l ng-checked=”true|false”: 是否选中复选框

    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    <script src="angular.min.js"></script>
    <script type="text/javascript">
        /*定义myApp模块*/
          var app = angular.module("myApp",[]);
    	/*将myAPP模块添加控制器*/
    	  app.controller("myController",function($scope){
    	       /*定义对象*/
    			$scope.value1="true";
    			$scope.value2="1";
    			$scope.value3="true"
    		 });
    </script>
    </head>
    <body>
      <div ng-app ="myApp" ng-controller="myController">
        复选框1:<input type="checkbox" ng-model="value1" /><br>
    	复选框2:<input type="checkbox" ng-model="value2" ng-false-value="1"
    	ng-true-value="2" />
        <br>
        复选框1选中值:{{value1}}<br>
        复选框2选中值:{{value2}}
    	<br>
    	<input type="checkbox" ng-model="value3" >全选</input>
    	<input type="checkbox" ng-checked="value3" >A</input>
    	<input type="checkbox" ng-checked="value3" >B</input> 
    	<input type="checkbox" ng-checked="value3" >C</input>
    	
      </div>
    </body>
    </html>

    结果:

    3.10 下拉列表框

    l ng-options="元素变量.键 as 元素变量.键 for 元素变量in 数组":选项值表达式绑定

    l ng-selected=”true|false”: 是否选中下拉列表框指定的选项

    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    <script src="angular.min.js"></script>
    <script type="text/javascript">
        /*定义myApp模块*/
          var app = angular.module("myApp",[]);
    	/*将myAPP模块添加控制器*/
    	  app.controller("myController",function($scope){
    	       /*定义对象*/
    		 $scope.list=[
    						{id:1,name:"haha"},
    						{id:2,name:"ssfd"},
    						{id:3,name:"sbdd"}
    					 ];
    		 });
    </script>
    </head>
    <body>
      <div ng-app ="myApp" ng-controller="myController">
       <select ng-model ="code" ng-options="city.id as city.name for city in list">
         <option value="">请选择</option>
    	 {{code}}
       </select>
       <br>
       <select>
          <option value="1">1</option>
    	  <option value="2" ng-selected="true">2</option>
       </select>
    	 
      </div>
    </body>
    </html>

     

    结果

     

    4 内置服务


    4.1 $http服务

    我们的数据一般都是从后端获取的,那么如何获取数据呢?我们一般使用内置服务$http服务来实现。

    4.1.1 $http()发送请求

    语法格式:

    $http({

    method : 'get|post', // 请求方式

    url : '', // 请求URL

    params : {'name':'admin'} // 请求参数

    }).then(function(response){ // 请求成功

    // response: 响应对象封装了响应数据、状态码

    },function(response){ // 请求失败

    // response:  响应对象封装了响应状态码

    });

    发送异步请求:
     

    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    <script src="angular.min.js"></script>
    <script type="text/javascript">
        /*定义myApp模块*/
          var app = angular.module("myApp",[]);
    	/*将myAPP模块添加控制器*/
    	  app.controller("myController",function($scope,$http){
    	    /*定义对象*/
    		$scope.httpGet = function(){
    		  $http({method:"get",
    				url:"mm.json"}).then(function(response){
    				  $scope.list = response.data;
    				},function(response){
    				alert("加载失败")});
    		 }; 
    		 });
    </script>
    </head>
    <body>
      <div ng-app ="myApp" ng-controller="myController" ng-init="httpGet()">
          <table border="2">
    	   <tr>
    	    <th>id</th>
    		<th>name</th>
    	   </tr>
    	   <tr ng-repeat="m in list">
    	     <td>{{m.id}}</td>
    		 <td>{{m.name}}</td>
    	   </tr>
    	  </table>
    	 
      </div>
    </body>
    </html>

    结果:

     

    4.1.2 $http.get()发送请求

    语法格式:

    // 第一种格式

    $http.get(URL,{  

        params: {  

           "id":id  

        }  

    }).then(function(response){// 请求成功

    // response: 响应对象封装了响应数据、状态码

    }, function(response){ // 请求失败

    // response: 响应对象封装了响应状态码

    });

    // 第二种格式

    $http.get(URL).then(function(response){ // 请求成功

    // response: 响应对象封装了响应数据、状态码

    },function(response){ // 请求失败

    // response: 响应对象封装了响应状态码

    });

    4.1.3 $http.post()发送请求

    语法格式:

    // 第一种方式

    $http.post(URL,{  

        "id" : id  

    }).then(function(response){ // 请求成功

    // response: 响应对象封装了响应数据、状态码

    },function(response){ // 请求失败

    // response: 响应对象封装了响应状态码

    });
     

    其实学Angular只要学它的指令就好了

    展开全文
  • 接触angular还有两个多月就要整整满一年了,从一个.net程序员变成了一个前端,在了解了前端的东西之后爱上了前端,怎么说呢,其实对于前端这种侧重数据展示的开发自己本身就喜欢,奈何没有引路人,各种原因之下最后...

    前言

    接触Angular还有两个月这样就要整整满一年了,从一个.net程序员变成了一个前端,在了解了前端的东西之后爱上了前端,怎么说呢,其实对于前端这种侧重数据展示的开发自己本身就喜欢,奈何没有引路人,各种原因之下最后进了.net的坑。好了,废话不多说,写下这篇博客其实也是对自己使用angular将近一年的总结,怕自己以后有些东西忘记,包含了环境安装,新建项目,组件,路由,指令,事件,管道,服务和代理等。

    Angular及其它框架介绍

    Angular是目前前端的三大框架,由谷歌进行开发维护,另外两个框架是React和Vue。React由Facebook 进行开发维护,Vue主要由国内开发者尤雨溪进行开发维护。

    从时间上看,Angular最早版本已经是十年之前,2009年谷歌发布Angular1,2016年9月Angular2正式版发布,Angular3由于在开发过程中出现问题(Router模块)被放弃,直接奔向4,2017年3月Angular4正式版发布,之后还有5、6、7,改动都不是很大,2019年5月28日,Angular8正式发布。其实这些版本中只有1.x是最特别的,因为1.x与2以及之后的版本完全不一样,可以说基本没什么关系了,在语法上就不一样,以前在学校的时候就接触1.x,在我那时看来,1.x的语法简直晦涩难懂,学习成本比较高。React是2013年5月正式发布,2015年逐渐稳定,由于对React并不是很了解,所以就不过多介绍了。Vue最早是2014年2月在GitHub开源,但是1.0版是在2015年10月发布的,2016年8月发布2.0版,预计今年下半年发布3.0,据作者说,3.0将会进行重写。

    在使用情况上,从国内来看,虽然Angular是最早发布的,但相对于其他的两个框架,现在Angular在国内的使用率并不高,甚至有些人断言Angular过时了,(嗯~~持这种观点的人我不想和他交朋友,因为我觉得其实Angualr挺好,就是国内生态不行,哈哈),使用率最高的是Vue,其次是React,造成这个的原因有一部分是因为Angular1到Angular2的跨度太大,导致开发人员学习成本的提高,迫使他们放弃,转向其他框架;另一部分原因我个人认为是在灵活性上以及上手难度上,相对于Angular来说,Vue十分的小巧与灵活,上手也比较快,由于Vue的小巧与灵活性,我更倾向于Vue是一个库或者模板引擎,当然,进行一个项目,前端上仅仅使用Vue是不够的,通常使用Vue还会使用其他的第三方东西,比如vue-router、vuex、axios,这些统称Vue全家桶。其实所谓的全家桶Angular中也有,但是Angular将他们都封装包含在一起了,使得这些东西成为Angular的一部分。就国外来说,其实Angular的使用率是极高的,远远将Vue甩在身后,当然,毕竟谷歌在国外的影响力可不是一点两点。虽然在国内Angular的状况有点惨,但不能否认的是,在构建大型项目上,Angular比Vue更为适合。叨叨了这么多,下面开始正题了。

    技术及工具准备

    • 1、安装node.js
      关于node.js,node其实是服务端的东西,安装它其实主要是使用它的npm工具包,又引入了新东西npm,它是node package manager的缩写,是一个包管理工具,安装了node之后,我们可以通过npm命令下载需要的包。嗯~~为什么需要npm,因为现在网络上有太多太多的包以及工具,有时候我们需要的时候得一个一个的去找,找到了才能下载,这样会很麻烦和不方便,而npm则帮我们把这些包管理起来,需要的时候直接运行npm install 命令就可以下载需要的包到我们的项目中。
    • 2、安装Typescript
      打开cmd运行命令:npm install -g typescript
      因为angular是用TypeScript写的,所以得安装。TypeScript是微软开发的,它是JavaScript的超集,引入了类的概念,嗯~~这一点对后端开发人员很友好啊。既然说它是JavaScript的超集,那么就算不了解TypeScripe也可以开发的,因为一开始我就不了解的,只要JavaScript没问题就行。虽然说Angular是用TypeScript写的,但在浏览器运行前它在底层还是要被编译成JavaScript的,毕竟浏览器不认识。
    • 3、安装Angular-cli
      打开cmd运行命令:npm install -g @angular/cli
      要说Angular-cli就先说说cli,cli全称command-line interface,即命令行界面,说白了就是通过动手敲下一个个指令让计算机工作,嗯~~为什么要用这个,得记一个个命令多累人,为什么没有可视化工具进行操作,这个我也不知道,难道就只是为了节约计算机系统资源?希望有人告诉我。Angular-cli就是针对Angular项目构建的脚手架,对应的Vue也有Vue-cli,React没接触过不了解。在安装过程中可能会出现各种问题,反正基本上就是被墙的原因,实在不行就用淘宝镜像。
    • 4、开发工具。其实开发工具是个人喜好,有很多开发工具可以使用,但是我想推荐的是vscode,插件库很爽啊。关于被墙的解决方法和推荐插件点击这里

    创建新项目

    创建Angular新项目的运行命令:ng new 项目的名字
    这个命令在命令窗口中或者vscode的终端中都可以,其中的ng代表的是Angular,不知道是从哪个版本开始,创建新项目会有以下两个询问,根据需要选择就可以了,网络良好的话创建不会有问题,如果被墙了那就创建失败。
    创建项目

    运行创建的项目

    把项目文件丢到vscode中,然后在终端中执行命令:ng serve。其实运行npm start一样能启动项目,但是其实npm start最后还是调的ng serve

    编译通过
    在编译完成之后,在浏览器中访问4200端口,看见下面这个说明项目构建成功,正常运行
    运行成功

    一些编码风格设置

    通过Angular-cli生成的项目,在编码风格上与自己的习惯不一致时,可以通过修改tslint.json文件中的配置,以下是我的一些习惯
    风格

    Angular项目目录结构介绍

    这里从网上找了一张图,来源已经不清了
    目录结构

    ngModule

    关于ngModule,中文官网上有这么一句话

    每个 Angular 应用都至少有一个 NgModule 类,也就是根模块,它习惯上命名为 AppModule,并位于一个名叫 app.module.ts 的文件中。引导这个根模块就可以启动你的应用

    这句话其实说的很明白了,就是NgModule 类是必须的,否则跑不起来。(关于引导,是在main.ts文件中,那是程序的入口,通常不需要改动这个文件里的东西)这个类接受一个元数据对象,这个对象中的属性是用来描述这个模块的,具体看下图
    在这里插入图片描述

    组件

    组件,顾明思议一组元件,它是Angular中一个重要的概念,通过命令ng g component 组件名称来生成,见下图
    组件
    在上图中,@Component 装饰器会指出紧随其后的那个类是组件类,并指定元数据,换句话说就是,如果没有@Component这个装饰器的存在,这个TopComponentComponent类就是一个普通的类,那么它将无法控制任何html模板,只有被@Component 装饰的类才具有控制html模板的能力。
    在定义生成组件之后,在需要的地方放置就能将组件展示到页面上,组件就是一个元件,一块砖,哪里需要哪里搬
    在这里插入图片描述在这里插入图片描述
    以上就是一个最基本的Angualr应用程序所应知道的基本知识点,下面说说一些开发中用到的东西。

    组件间通讯

    组件就是一个个小模块,正常情况下他们都是没有关系的,数据之间不互通,但是一个应用中不可能数据都只在一个个模块中,必须进行一些数据交互才能完成相应的功能,因此组件的通讯就变得很重要。组件间通讯的场景主要有:一、嵌套组件间通讯。分为父组件向子组件传递数据、子组件向父组件传递数据两种情况;二、非嵌套组件组件通讯(如果不是这次的回顾,我都不知道非嵌套组件间通讯的这种官方方式,如果早知道,现在项目中就没有那么多骚操作了…)。

    • 嵌套组件间通讯

    1、父组件向子组件传递数据
    步骤1:在子组件选择器标签上进行属性绑定,所绑定的值为父组件的某个属性,也就是你要传递给子组件的值

     <out #child [requestData]="sendToChild" (sendToParent)="getOutput($event)"></out>
    

    上面的代码片段中[requestData]="sendToChild"就是进行进行的步骤1,requestData是子组件out的接收变量名,sendToChild是父组件中的一个属性,它的值如果发生变化,子组件所接收到的值也会立即变化。

    步骤2:在组件的.ts文件中使用@Input()属性装饰器进行接收

    @Input()
    requestData:string;
    

    至此,只要父组件中sendToChild的值发生变化,子组件requestData的值也就会马上变化。

    2、子组件向父组件传递数据
    步骤1:先定义属性装饰器@Output()

    @Output()
    sendToParent:EventEmitter<string>=new EventEmitter();
    

    关于EventEmitter类,我说不太清楚,没有专门去了解,就知道用来发射对象或属性给父组件的。要注意的是,这里的EventEmitter类是@angular/core里引入的,不能是其他模块里的,比如events里也有EventEmitter类,别搞错了。

    步骤2:主动触发发射(当然也可以是代码逻辑发射)

    <input type="text" placeholder="往父组件中传入的值" [(ngModel)]="toParent">
    <button class="btn btn-primary" (click)="sendToPar()">确定</button>
    
    toParent:string;
    sendToPar(){
        this.sendToParent.emit(this.toParent);
    }
    

    通过emit方法将要发射的值发射出去。
    上面是子组件进行了发射的相关步骤,下面是父组件的步骤

    步骤3:要接收谁的值就去它的选择器上进行监听

    <out #child [requestData]="sendToChild" (sendToParent)="getOutput($event)"></out>
    

    (sendToParent)="getOutput($event)"所绑定的事件sendToParent必须是子组件中的EventEmitter实例。

    requestData: string;
    getOutput(event: string) {
        this.requestData = event;
    }
    

    3、父组件调用子组件的属性与方法
    这种方式是通过@ViewChild来实现的,就像是new了一个子组件的实例一样。

    步骤1:给子组件定义模板变量

      <out #child [requestData]="sendToChild" (sendToParent)="getOutput($event)"></out>
    

    #child就是模板变量,在当前HTML页面中都可以使用,在.ts文件中我的理解就像document.getElementById()

    步骤2:使用@ViewChild()属性装饰器注入到父组件中

    @ViewChild("child")
    childRecive: OutputComponent;
    

    经过@ViewChild()装饰的属性childRecive将会成为OutputComponent的实例(不知道这么说对不对)。这里的OutputComponent是子组件out的类,如果使用模板变量的标签是普通HTML标签,则类型为:ElementRef。经过这个两个步骤,父组件就可以调用子组件中的方法和属性了。

    关于模板变量的的另一种使用,官网上还有一种是父子组件通过本地变量互动,其实就是利用模板变量在当前HTML中任何地方都可以使用的特性,这里就不写了。

    4、ng-content内容投射
    组件间的交互官网上并没有提到这种方式,但我的觉得这也是一种交互吧,毕竟投射的内容可以直接使用父组件中的东西

    步骤1:在子组件选择器标签中写HTML代码片段

    <out #child [requestData]="sendToChild" (sendToParent)="getOutput($event)">
        <!-- 
          选择器之间是可以写HTML代码片段的,这些片段将会显示在这个组件(outcomponent)的模板中,
          前提之一是这个组件的模板中有调用了ng-content指令,一般的关系是从父组件到子组件,这里
          还可以进行插值绑定获取其他的数据的绑定等,所绑定的值是父组件的值
        -->
        <div class="header" style="color:red;">这是头:这个是在父组件中的写的代码显示到了子组件中</div>
        <div>这个是在父组件中的写的代码显示到了子组件中,这是父组件中的属性:
        	<span  style="color:red;">{{context}}</span>
        </div>
        <div class="footer" style="color:red;">这是脚:这个是在父组件中的写的代码显示到了子组件中</div>
    </out>
    

    步骤2:在子组件的HTML文件中使用ng-content标记投射点

    <div style="border:1px solid darkslateblue;">
        <!-- 标记投影点,从父组件投影部分HTML代码片段过来在这个位置显示 -->
        <ng-content select=".header"></ng-content>
        <ng-content></ng-content>
        <ng-content select=".footer"></ng-content>
    </div>
    

    select属性支持css选择器(”#id”,”.class”等等)
    结果如下:
    在这里插入图片描述

    • 非嵌套组件组件通讯

    对于非嵌套组件组件通讯,目前我所知道只有通过service了,通过service形象点说就是桥,或者容器,一方将数据放入这个容器,另一方需要的时候进行读取,实现如下:
    步骤1:创建一个service,命令:ng g service 服务的名称
    步骤2:创建好service之后,编写接收函数和读取函数

     message:string;
     sentMessage(message:string){
        this.message=message;
     }
     getMessage(){
        return this.message;
     }
    

    步骤3:在需要的地方注入服务就可以使用了

    constructor(
        private messageService:MessageService
    ){}
    //要发送消息的组件调用服务
    sent(){
        this.messageService.sentMessage("发送的消息");
    }
    //要获取消息的组件中调用服务
    message:string;
    getMessage(){
        this.message=this.messageService.getMessage();
    }
    

    注入了服务就可以使用服务里的属性和方法了,就不展示结果了,很简单的东西

    路由

    这里的路由指的是前端路由,关于路由的概念,我找不到一个明确的定义,总结网上解释最多的是

    路由就是指随着浏览器地址栏的变化,展示相应的页面给用户

    虽然我能理解这样的解释,也认同这种解释是对的,但我并不想接受这种解释,因为这不是我想要的解释,但是我也没有什么语言来准确解释。嗯~~我觉得我的这种思想很奇怪。对于前端路由,GitHub上有一个人总结的很到位,参考这里

    那么谈谈我自己对于路由的理解。路由原本是属于后端的东西,用户地址栏输入地址或者在页面进行操作之后会向服务器发起请求,那么服务器则会对请求的URL进行解析,然后将数据返回给客户端。随着业务需求的复杂,服务端将会处理越来越多的请求,每一次请求都要返回相应的数据,这些数据中有些根本就不重要,但是仍然需要进行返回,尤其是需要进行整个页面刷新的,这样一来服务端所承担的压力会越来越大,那怎么来减小这里压力呢。

    前端路由就这么应运而生了,它的诞生是借鉴与浏览器的导航模式,我们知道的是,当地址栏的URL不同将会请求到不同的页面,只要URL发生了变化就马上发起请求,刷新页面,那么这个在前面说了,会使得服务端的压力增大,但如果我的地址栏发生了变化但是不发起请求,我客户端根据地址栏变化的东西对应展示写好的东西,那么服务端不就没事了,就算需要数据只要返回给我一个赤裸的数据就够了,所以这就是前端路由的思想。现在开发中的前后端分离我们可以简单粗暴的这么认为,前端主要就是DOM,是衣服,后端是数据,是各种人。当前端渲染页面的时候就是指定展示某件衣服,那么后端就返回这件衣服对应的人,这个人是赤裸的,这样一结合就是一个体面的人。

    上面说了只要地址栏发生了变化,但不发起请求,那么后端就没什么事了,但问题是地址栏URL发生了变化怎么让它不向服务器发起请求呢,解决方法就是监听浏览器的hash值变化,诶,问题又来了,什么是hash值呢。

    hash在w3school上的定义是:

    hash 属性是一个可读可写的字符串,该字符串是 URL 的锚部分(从 # 号开始的部分)。

    这个定义说的很明白了,比如这个URLhttps://music.163.com/#/friend#/friend就是这个URL的锚部分,这个#号后面的friend就是hash值,这个值或者后面的值(如果有)不管怎么变化都不会引起页面的请求,没有请求就不会刷新页面了,但需要知道的是,虽然它不会发生请求,但是访问历史是改变的。

    下表是关于路由的关键词汇

    路由器部件 含义
    Router(路由器) 为激活的 URL 显示应用组件。管理从一个组件到另一个组件的导航
    RouterModule 一个独立的 NgModule,用于提供所需的服务提供商,以及用来在应用视图之间进行导航的指令。
    Routes(路由数组) 定义了一个路由数组,每一个都会把一个 URL 路径映射到一个组件。
    Route(路由) 定义路由器该如何根据 URL 模式(pattern)来导航到组件。大多数路由都由路径和组件类构成。
    RouterOutlet(路由出口) 该指令()用来标记出路由器该在哪里显示视图。
    RouterLink(路由链接) 这个指令把可点击的 HTML 元素绑定到某个路由。点击带有 routerLink 指令(绑定到字符串或链接参数数组)的元素时就会触发一次导航。
    RouterLinkActive(活动路由链接) 当 HTML 元素上或元素内的routerLink变为激活或非激活状态时,该指令为这个 HTML 元素添加或移除 CSS 类。
    ActivatedRoute(激活的路由) 为每个路由组件提供提供的一个服务,它包含特定于路由的信息,比如路由参数、静态数据、解析数据、全局查询参数和全局碎片(fragment)。
    RouterState(路由器状态) 路由器的当前状态包含了一棵由程序中激活的路由构成的树。它包含一些用于遍历路由树的快捷方法。
    Link parameters array(链接参数数组) 这个数组会被路由器解释成一个路由操作指南。你可以把一个RouterLink绑定到该数组,或者把它作为参数传给Router.navigate方法。
    Routing component(路由组件) 一个带有RouterOutlet的 Angular 组件,它根据路由器的导航来显示相应的视图。

    说了一堆概念的东西了,现在说说使用(这篇博客对应的demo我是事先写好了的),下图中涉及了路由的大部分知识,路由配置、传参方式、路由守卫等,这里只是配置,相对应的其他地方也要有相应的配置。
    路由配置图:
    在这里插入图片描述

    关于路由传参,有三种方式

    • 第一种:URL传参。
      1、进行路由配置见上图。
      2、配置好之后在routerLink上配置、传参,如下
     <button class="btn btn-primary" routerLink="./router-child2/{{id}}/{{name}}">路径传值</button>
    

    3、在对应的组件中接收参数。
    在这里插入图片描述
    4、最终结果:
    点击传值后路径上将携带参数值http://localhost:4200/router/router-child2/123/张三
    在这里插入图片描述

    • 第二种:路由配置传参
      1、在路由配置中添加data属性和值就可以,见路由配置图。
      2、配置routerLink
    <button class="btn btn-primary" routerLink="./router-child3">配置传值</button>
    

    3、在对应的组件接收参数

    this.router.data.subscribe(pram=>{
          console.log(pram);
    })
    

    4、接收结果:
    在这里插入图片描述

    • 第三种:查询参数传参
      查询参数传参不需要配置路由
      1、配置routerLink和queryParams
     <button class="btn btn-primary" routerLink="./router-child" [queryParams]='{id:id}'>查询参数传值</button>
    

    2、在对应组件接收参数

    this.router.queryParams.subscribe(params=>{
          this.id=params["id"];
    })
    

    3、最终结果:
    通过查询参数传值时,URL会携带参数值:http://localhost:4200/router/router-child?id=123456
    在这里插入图片描述
    关于路由参数传参的三种方式介绍结束。在这之中要注意的地方有:

    • 关于routerLink的写法
      一种是写在a标签里的,一种是非a标签里的
      a标签中可以使用这种方式:[routerLink]="['./router-child',id,name]"
      非a标签中不能有中括号或者什么其他的符号,否则报错或者匹配失败:易出现的问题有:
      1、[routerLink]="[./router-child]"该方式直接导致报错,routerLink不需要加中括号
      2、routerLink="[./router-child,id]"该方式导致路径不对,找不到匹配路径,routerLink的值不需要加中括号,添加中括号时,中括号会转码加到路径中导致匹配失败

    • 关于子路由
      添加子路由时,routerLink的值需要在斜杠/的前面加.不加.时将直接到根路由寻找,如果匹配到相同的路径则显示相应的组件,匹配不到则匹配**路径 。

    • 上述例子中URL中没有#
      对于URL中没有#号,这是因为路由器通过两种 LocationStrategy 提供商来支持不同的URL风格
      一种是:PathLocationStrategy - 默认的策略,支持“HTML 5 pushState”风格。
      另一种是:HashLocationStrategy - 支持“hash URL”风格。
      RouterModule.forRoot() 函数把 LocationStrategy 设置成了 PathLocationStrategy,使其成为了默认策略。
      关于这个的原因,angular官网上已经解释的很清楚,详情可见官网中路由与导航部分的附录

    路由导航补充:路由导航除了在配置routerLink,还可以通过跳转的方式来进行,见以下

    <button class="btn btn-primary" (click)="navigateTO()">navigate跳转</button>
    
    navigateTO(){
        this.router.navigate(["router/router-child3",{id:"xxxx",name:this.name}]);
    }
    

    路由的东西暂时就写这么多吧,还有路由守卫的,这里就不写了,就是在路由配置里加路由守卫属性,然后编写相关守卫类,返回布尔类型,交给提供商providers,根据true和false决定是否允许进入和离开路由

    指令

    关于指令,怎么解释这个词在angular中的定义呢,通俗点说就是一个命令,当你把这个命令绑在了一个标签上,那么它就会对这个标签进行一些操作,这个指令的背后就是一些操作代码,通过指令,我们可以在很多地方使用,但是操作代码就一套,省了很多事情。指令分为属性型指令和结构型指令。一般情况下angular的内置指令就足够我们使用了,有以下这些常见指令:

    • ngIf =====if判断,为真则显示该部分,为假则不显示
    • ngFor ====for循环,循环输出或显示
    • ngSwitch ==switch语句,符合条件则显示
    • ngClass ===设置css类
    • ngStyle ====设置样式

    这几个指令是开发中经常用到的,也没什么难度,没什么好说的

    对于Angualr,通过命令生成的相关组件、指令、管道等,都会自动在根组件注册相关类,但如果是自己手动写相关的装饰器和类等,则需要手动去根组件注册这个类。

    • 属性型指令

    属性型指令用于改变一个 DOM 元素的外观或行为。这里演示一个扩展官网例子的。
    步骤1:执行命令ng g directive 指令名称,生成的文件中可见@Directive()装饰器

    @Directive({
      selector: '[appHighlightAndResetSize]'
    })
    

    步骤2:注入宿主 DOM 元素的引用
    使用命令创建指令后生成的文件除了基本的@Directive()装饰器和类这些东西,空荡荡的宛如被掏空,此时要在构造函数中注入宿主 DOM 元素的引用

    constructor(
        el:ElementRef
    ) { }
    

    在注入宿主 DOM 元素的引用之后,如果不需要参数以及行为,则可以直接在构造函数的方法体中写相应的操作逻辑代码,下面的两个步骤也就不需要了。

    步骤3:定义输入属性(可选,如果需要传入参数则需要此步骤,反之不要)

     @Input("appHighlightAndResetSize")
     colorAndSize:any;
    

    步骤4:定义行为函数(可选,如果有行为事件则需要此步骤,反之不要)

     @HostListener("mouseenter")
      onMouseEnter(){
        console.log(this.colorAndSize);
        this.el.nativeElement.style.backgroundColor=this.colorAndSize.color;
        this.el.nativeElement.style.fontSize=this.colorAndSize.size+"px";
      }
      @HostListener("mouseleave")
      onMouseLeave(){
        this.el.nativeElement.style.backgroundColor=null;
        this.el.nativeElement.style.fontSize=null;
      }
    

    这个@HostListener()装饰器是用来监听dom事件的,第一个参数是要监听的事件,第二个参数可选,是当该事件发生时传给处理方法的一组参数。
    结果演示如下:
    鼠标进入前:
    在这里插入图片描述
    鼠标进入后:
    在这里插入图片描述

    • 结构型指令

    对于自定义结构型指令,我不知道是怎样的需求才会需要这样,通常情况下ngIfngForngSwitch就够用了,但是对于学习来说,知道如何去自定义还是有必要的,由于不知道怎样的需求才会需要自定义结构型指令,因此这里直接拿官网的例子来了。

    步骤1:执行命令ng g directive 指令名称,生成的文件中可见@Directive()装饰器。当然也可以手动导入相应的装饰器和相关的类,并最后注册到根组件

    @Directive({
      selector: '[appUnless]'
    })
    

    步骤2:构造函数中注入模板类和视图容器类

    constructor(
        private templateRef:TemplateRef<any>,
        private viewContainerRef:ViewContainerRef
    ) { }
    

    步骤3:导入@Input()属性装饰器并编写逻辑代码

      private hasView: boolean = false;
      @Input()
      set appUnless(condition: boolean) {
        if (!condition && !this.hasView) {
          this.viewContainerRef.createEmbeddedView(this.templateRef);
          this.hasView = true;
        }
        else if (condition && this.hasView) {
          this.viewContainerRef.clear();
          this.hasView = false;
        }
      }
    

    使用结果:
    在这里插入图片描述
    在这里插入图片描述
    结构型指令相对来说比较难,而且一般来说没必要自定义结构型指令(仅我个人见解),自定义结构型指令两个重要的类TemplateRefViewContainerRefTemplateRef可以取得<ng-template>的内容,ViewContainerRef可以访问视图容器,通过这两个类就可以完成对页面DOM结构的更改,至于更深的对于DOM的相关操作我就不知道了

    事件

    事件本来想合到指令里写的,但是觉得不合适,还是分了出来,其实angualr事件我所了解的并不多,只知道有哪些常见事件,以及如何使用,但都不难。常见事件有:

    • ngClick =========点击事件
    • ngBlur ==========失焦事件
    • ngFocus ========获焦事件
    • ngKeyup ========按键抬起事件
    • ngMouseenter ====鼠标进入事件
    • ngMouseleave ====鼠标离开事假

    这些常见事件也都很简单,每个事件都有一个对应的$event的事件对象,这个对象的具体取决于事件类型,使用的时候把它打印到控制台找自己需要的属性与方法就可以。

    事件也可以自己自定义,这里就不写了,官网有个小例子。对于内置的事件具体有哪些,我个人是不清楚的,有时候就拿原生DOM事件去试,毕竟我找不到官网在哪里写有。

    对于ngKeyup有一个事件过滤就是keyup.enter这个就是只在按了回车键之后才调用函数,对于angualr的事件过滤,我仅知道这一个,这一点上Vue似乎做的更好
    使用方法:

    <input #box (keyup.enter)="onEnter(box.value)">
    

    管道

    对于管道其实也是一个常用的功能,就是将数据格式化或过滤展示到界面,通常的需求就是,从数据库读取过来的数据有时候格式不是日常生活中所见到的格式,比如日期;还有一些比如性别,存入数据库时候可能用0和1表示男女,但读出来的不可能将0和1直接展示给用户,这就需要将读出来的数据进行处理。Angualr就提供了这种功能,通过管道将数据格式化展示,使用方法就是在数据的后面添加管道操作符|然后写上对应管道,比如格式化日期:{{ 要格式化的日期 | date:'yyyy-MM-dd' }},date就是日期管道,yyyy-MM-dd就是要格式化成样子,格式可以自己去定义。比较常用的内置管道有:

    • date =========格式化日期
    • upperCase ====转大写
    • lowerCase ====转小写
    • json =========格式化json,不好用

    通常情况下内置的管道不符合我们个人开发的需要,很多时候需要自定义,这里演示一个性别的管道

    步骤1:指令命令ng g pipe 管道名称
    通过命令生成的文件中,初始代码为

    @Pipe({
      name: 'gender'
    })
    export class GenderPipe implements PipeTransform {
    
      transform(value: any, args?: any): any {
        return null;
      }
    
    }
    

    @Pipe()装饰器标记相邻的这个类是一个管道,管道类实现了 PipeTransform 接口的 transform 方法,该方法接受一个输入值和一些可选参数,并返回转换后的值。

    步骤2:在transform方法中编写处理逻辑

     if(value=="1"){
          return "男";
     }
     else if(value=="0"){
          return "女";
     }
     else{
          return "人妖";
     }
    

    步骤3:
    如果数据源为:

    person = [
        {name: "张三",sex: "1"},
        {name: "小明",sex: "3"},
        {name: "小红",sex: "0"}
    ]
    

    使用:

    <li *ngFor="let item of person" >{{item.sex | gender}}</li>
    

    结果过展示为:
    在这里插入图片描述
    关于管道需要注意的地方就是纯管道非纯管道的区别:
    只有发生纯变才会调用该管道,这类管道称为纯管道,其余的管道成为非纯管道。 纯变指的是对基本数据类型(StringNumberBoolean)输入值的变更或者对对象引用ArrayFunctionObject)的更改。 只要数据发生改变,均会触发非纯管道,但不一定会触发纯管道,需要考察数据变化的情形是否为纯变化。
    这里换句话说就是像数组、对象等数据的改变,只有当引用地址的改变才会调用管道,如果只是数组、对象中的某一个值改变是不会调用管道的。

    服务与代理

    服务其实在非嵌套组件间通讯已经使用过,只不过没有细说,关于服务,先扯一扯依赖注入吧,依赖注入一开始我一直不理解是怎么一回事,在网上查了很久,解释千篇一律,很少有自己见解的,有些还会扯到控制反转的,并不是说说的不对,而是不利于那些什么都不懂的人去理解。

    我理解的依赖注入是:
    在没有依赖注入的时候,A要完成某个功能需要B、C、D的帮助,那么A就需要亲自一个一个的去叫B、C、D帮忙,在面对对象编程语言中,就是需要new B、C、D对象,那么问题来了,A直接与B、C、D产生了关系,这在软件工程中就是提高了耦合。而有依赖注入的时候,有一个人力资源公司把B、C、D都收了,A要完成功能的时候直接去找人力资源公司说我需要B、C、D就够了,最后人力资源公司给A提供B、C、D,至于人力资源公司怎么找的B、C、D不关A的事。这样就降低软件的耦合。

    Angular的依赖注入有不少东西,我并不能完全的理解,对于依赖注入的好处,我所能理解的就是降低耦合,降低了内存占用(因为如果使用每new一次就要占用一个内存空间),其他的我就不知道有什么好处了。但是话说回来,依赖注入是一个框架所拥有的东西,一个框架的目的就是统一生产形式,规范生产过程,如果将一个使用了框架的代码交给你,你直接知道从哪里看起,但是如果给你一个没有生产规范的代码给你,你会感觉无从下手,甚至会被各种依赖之间绕晕。

    在Angular中使用ng g service 服务名称命令之后生成的初始代码为:

    @Injectable({
      providedIn: 'root'
    })
    export class HttpService {
    
      constructor() { }
      
    }
    

    @Injectable()装饰器是每个 Angular 服务定义中的基本要素,它把与之相邻的类标记为可供注入的服务,在@Injectable()中有一个providedIn的元数据选项,它的值为root,表明这个类在顶层提供服务,这么定义之后就不需要将它添加到根模块的提供者中。这个元数据选项的值不一定非得为root,可以根据自己的需要修改,如果指定这个服务提供给哪个具体的类,那么需要将这个服务类注册到根模块的提供者providers中。

    这里演示一个简单的请求后端数据的服务,要了解更过参考这里代理到后端服务器部分。
    步骤1:必须先在根模块中导入HttpClientModule模块,否则在其它地方无法正确引包

    imports: [
        BrowserModule,
        // 导入HttpClientModule需要在BrowserModule模块的后面
        HttpClientModule,
    ],
    

    步骤2:把 HttpClient 注入到应用类中

    @Injectable({
      providedIn: 'root'
    })
    export class HttpService {
    
      constructor(
        private httpService:HttpClient
      ) { }
      
    }
    

    这一步之后还不能获得服务器数据,因为没有配置代理,会产生跨域的问题,因此要使用HttpClient的相关API请求数据,需要先配置好代理

    步骤3:配置代理

    1. 在项目的 src/ 目录下创建一个 proxy.conf.json 文件,和 package.json 放在同一目录下
    2. 往这个新的代理配置文件中添加如下内容:
    {
      "/api": {
        "target": "http://localhost:3000",
        "secure": false
      }
    }
    
    1. angular.json 中为 serve 目标添加 proxyConfig 选项:
    "architect": {
      "serve": {
        "builder": "@angular-devkit/build-angular:dev-server",
        "options": {
          "browserTarget": "AngularTest:build",
          
          "proxyConfig": "src/proxy.conf.json"
          
        },
    

    也可以在package.json的命令后面直接以参数的形式配置

    "scripts": {
        "ng": "ng",
        
        "start": "ng serve --proxy-config proxy.config.json --port 4300",
        
        "build": "ng build",
        "test": "ng test",
        "lint": "ng lint",
        "e2e": "ng e2e"
      },
    

    经过以上配置之后就可以使用HttpClient相关的API了,比如get请求

     getServe():Observable<any>{
        return this.httpService.get("api/");
      }
    

    HttpClient的很多API返回的都是Observable流,关于Observable就不解释了,太多东西了。
    我自己搭了一个node服务器对请求进行了响应,返回了一个测试数据
    在这里插入图片描述

    展开全文
  • angular(1)

    2018-09-03 00:30:10
    写习惯了,下面是我的读书笔记,准备一点点深入学习Angular. 温故而知新 1.确保已经安装nodejs. 2.打开命令行窗口,进入F盘(我的在F盘,你可以选择其他) 键入:  ng new hello-angular   这个过程会有点慢,因...
  • Angular学习之个人浅谈

    2018-10-21 11:59:26
    现如今的前端框架蓬勃发展,已经产生了各种各样的前端框架,其中比较主流的像Angular、React、Vue等,都是基于MVVM思想开发的前端框架。 为什么选择Angular? 当然是因为公司在用angular了,目前一直在用新的...
  • Angular8 开发(二)

    2019-09-24 11:07:12
    前面已经说到了基本的集成可开发准备工作,Angular 开发(一)。接下来开始逻辑部分的编写 目录大纲段子列表获取,路由跳转详情获取段子详情音乐列表搜渲染搜索的音乐列表和播放音乐总结 段子列表获取,路由跳转...
  • 定义和用法 ... ...ng-change 指令需要搭配 ng-model 指令使用。...AngularJS ng-change 指令指令不会覆盖原生的 onchange 事件, 如果触发该事件,ng-change 表达式与原生的 onchange 事件都会执行。...
  • angular *Ngif else用法

    2019-05-25 19:02:57
    NgIf 指令 ngIf 指令用于根据表达式的值,在指定位置渲染then 或 else 模板的内容。 then 模板除非绑定到不同的值,否则默认是 ngIf 指- 令关联的内联模板。 else 模板除非绑定对应的...--Angular 2.x中使用templat...
  • Angular快速入门

    2018-06-26 11:43:05
    本指南的目标是使用Angular CLI在TypeScript中构建和运行一个简单的Angular应用程序,同时遵守有助于每个Angular项目的风格指南建议。到本章结束时,您将通过CLI了解开发的基本知识,并为这些文档样本...
  • 由于Angular4升级了,旧版的Angular-Cli支持性不是很好,所以Angular-Cli也需要升级更新,本质就是删除掉以前的,再重新安装就好了。Angular-Cli is more than tool,it is a platform!一、安装Angular-Cli经过n次的...
  • requirejs + angular + angular-route 浅谈HTML5单页面架构  众所周知,现在移动Webapp越来越多,例如天猫、京东、国美这些都是很好的例子。而在Webapp中,又要数单页面架构体验最好,更像原生app。简单来说...
  • angular9拦截器的使用

    2020-07-06 22:10:29
    angular9拦截器的简单使用拦截器统一添加token拦截器使用拦截器实现后的效果参考资料 拦截器统一添加token 我们在做一个后台管理系统时,需要给每个请求的请求头里面添加token,所以下面我们来了解一下angular的拦截器...
  • 我们可能会发现按照网上的方式下载安装后,使用Angular CLI生成的项目并不是我们想要的Angular的版本,因为在我们没有指定安装版本的前提下,默认会下载最新的版本安装,然而不同的Angular CLI版本在生成项目时默认...
  • 按条件加载组件,实现组件的灵活切换,减少大量ngIf的使用,在angular中也是比较常见的操作,下面就来大家一起交流一下angular组件的动态使用. 指令的创建 在添加组件之前,先要定义一个锚点来告诉 Angular 要把组件插入...
  • Angular引入第三方库

    2019-03-19 16:07:06
    如果我们想在Angular中使用第三方的库,比如jquery或bootstrap等,该如果做呢?首先我们先来看看package.json这个文件,在目录介绍那篇博客中我们已经知道,package.json这个文件列出了项目所使用的第三方依赖包。...
  • angular原理及模块简介

    2016-11-22 20:56:24
    本人前端小白,奈何在公司在做一个PC端的程序,用angular写,不得不自学了一下angular框架。虽然在工作过程中勉强勉强够了,但是觉得既然用了就稍微了解得全面一点,所以花了几个晚上看了一下angular的developer ...
1 2 3 4 5 ... 20
收藏数 123,189
精华内容 49,275
关键字:

angular