Angular以及生态圈
vue的开发流程是组件化开发
angular的开发流程是模块化开发 而一个模块是可以包含很多组件
1、设计原则 ①YANGNI You Aren’t Gonna Need It 不要写不需要的代码 ②KISS Keep it simple and stupid 保证代码足够的简洁 ③DRY Don’t Repeat Yourself 要学会封装和复用 ④高内聚 低耦合 耦合度:不同模块/不同组件之间的关联度 ⑤SRP single responsibility principle 单一责任原则 一个文件、一个方法、一个变量只做一件事情
⑥OCP(对于扩展开发 对于修改关闭) Open Closed Principle 开闭原则
2、angular生态圈概述 angular(包含了很多模块,form/http/router…) 第三方: ionic (移动端) ant-design(NgZorro) (pc/mobile) 官方material (pc/mobile) …
3、angular概述 what? angular是由Google在09年所推出的js的框架 (将框架比作一个坦克,学会如何实现基础操作,然后才能正确的用起来 将库比作一个瑞士军刀,专注一个细节) when? angular主要用来实现中大型、大型的SPA(单一页面应用程序) why? ①采用typescript(ts) 是由微软所推出的一个基于es6的超集 是一个强类型约束的语言 ②内置了非常多的模块和功能 可以给开发提供更多的选择 ③angular的速度 ④强大的cli工具 (cli:command line interface命令行交互界面 GUI:graphical user interface 图形化用户界面)
how? 统一node版本: https://nodejs.org/dist/v8.11.1/
将 C:\xampp\htdocs\codes\forStu\ng的Angular.rar拷贝到C:\xampp\htdocs\codes\ng
启动开发服务器:npm start 怎么预览效果:http://localhost:4200
官方推荐步骤: ①npm install -g @angular/cli ②ng new myapp ③cd myapp ④npm start/ng serve
4、angular基础语法 组件: 创建: ng g component demo01 调用: 作为子组件来调用:将组件类的装饰器中selector属性对应的值作为标签来进行调用
练习:(:- 15:50) ①创建一个组件 demo02-lianxi ②修改组件的模板内容 在html指定一个无序列表 ③到根组件的html中进行调用常见指令: 指令? 在angular中 指令是为了增强html的功能
{{}} *ngFor 循环 <any *ngFor="let tmp of list;let myIndex=index"></any> *ngIf 条件 <any *ngIf="expression"></any> div [ngSwitch]="expression" p *ngSwitchCase="result1" p *ngSwitchCase="result2" p *ngSwitchDefault (click)="" 事件绑定 [href]="" 属性绑定 [(ngModel)]="" 双向数据绑定(准备工作:FormsModule app.module.ts import {FormsModule} from '@angular/forms' @NgModule({ imports:[FormsModule] }) ) 注意事项: ①多个结构型指令不可以同时使用,借助于ng-container ②如果判断条件较多,建议使用ngSwitchCase 课后练习: ①准备两个组件 demo05-header demo05-cart ②将demo05-cart作为根组件模块的内容去调用 ③在demo05-cart调用demo05-header (:- 10:50) 练习: 完成demo07-lianxi的创建和调用(根组件模板调用) [(ngModel)] (click) *ngFor ①模板内容 input button(add) ul ②功能 点击add按钮,获取输入框的值,显示在ul的li常见管道(就是之前的过滤器filter/pipe): 1、本质:就是一个有参数有返回值的方法
2、目的:为了将数据更好的呈现在视图中,可以对数据执行一些筛选、过滤、格式化的处理。。 3、语法: <any>{{expression | myFilter:1:2 | myFilter}}</any> 4、内置: ①uppercase/lowercase ②slice ③number:'3.2-4' ④json (序列化JSON.stringify 反序列化JSON.parse) ⑤percent ⑥currency 5、自定义管道的创建和使用: ①创建 ng g pipe order ②实现管道的细节 transform(value:any,args?:any){ //根据管道本身的需求,针对value和args做处理,最后一定要记得返回处理后的结果 } ③调用管道(和内置管道用法一致) {{expression | order}} 练习:(:-14:45) ①创建一个gender的管道 ②在gender中实现以下功能 {{0 | gender }} -->女 {{0 | gender:true }} -->girl {{0 | gender:false }} -->女 {{1 | gender }} -->男 。。。service:服务 将不同的组件 要共同用到的数据或者方法封装在服务中,以方便复用 比较常用的服务:日志类、网络通讯。。。 服务的创建和使用: ①创建ng g service ** @Injectable
②方法的封装 .. ③调用 import {LoggerService} from '../logger.service' constructor(private myService:LoggerService){} this.myService.**5、组件间通信:(重点) props down(通过属性来实现父->子的通信) 回顾vue: vue.component(‘son’,{ props:[‘myValue’]//this.myValue }) Angular:
import {Input} from '@angular/core' @Input() myValue="" //this.myValueevents up(通过事件来实现子->父的通信) 回顾vue: 父: handleEvent(msg){//msg就是123} <son @myEvent="handleEvent( e v e n t ) " > < / s o n > 子 : t h i s . event)"></son> 子: this. event)"></son>子:this.emit(‘myEvent’,123) angular: 父: 绑定 handleEvent(msg){//msg就是123} <son (myEvent)=“handleEvent($event)”> 子: 触发 import {Output,EventEmitter} from ‘@angular/core’ //定义一个输出属性:支持触发myEvent事件的事件触发器 @Output() myEvent = new EventEmitter()
this.myEvent.emit(123)练习: ①创建两个组件 demo12-list demo12-item ②demo12-item li = span + button(delete) ③demo12-list 准备一个数组 myList=[100,200,300] 模板:ul是根据myList动态创建多个demo12-item;同时将数组中的临时变量传递给demo12-item1(接收并显示在span) (:- 10:25) ④点击demo12-item的delete按钮时,将值(0)传递给demo12-list(父组件接收到 打印在console) 子-》父 步骤1:调用子组件时 绑定事件delEvent 步骤2: 子组件引入 Output,EventEmitter,在点击delete按钮时触发事件,将0传递过去 (:- 10:55) 步骤3:将传递的值改成真实的下标 步骤4:父组件收到下标之后,从myList中删除该下标的元素
6、网络通信 ajax $.get/post axios fetch HttpClient
基本步骤: ①准备工作 找到根模块,引入HttpClientModule,放在imports数组 ②在需要发送网络请求的组件引入 import {HttpClient} from ‘@angular/common/http’
constructor(private myHttp:HttpClient){} //subscribe 订阅 this.myHttp.get().subscribe((result)=>{ //result就是服务器端所返回的数据 }) 练习:(:- 14:20) ①完成demo14-lianxi的组件的创建和调用 ②在组件的html 放置一个button,点击button,请求"http://localhost:8080/product/detail?lid=1" ③将请求来的商品的title 接收,显示在demo14-lianxi的html的h17、路由 两个问题: ①spa? single page application 单一页面应用程序 只有一个完整的页面,根据不同的url来载入一些代码片段到页面中显示 ②spa的工作原理 步骤1:解析地址栏 http://localhost:4200#/login 步骤2:解析地址栏中的路由地址信息 步骤3:遍历路由词典(路由数组),匹配和当前路由地址一致的路由对象 步骤4:将组件载入到指定的容器中,显示
7.1 基础用法 准备工作: 创建:ng g module my-demo --routing 调用:在app.module.ts 引入 放在imports ①指定容器 ②配置路由词典(由多个路由对象构成的数组) const routes:Routes = [ {path:"***",component:***} ] ③调用路由 RouterModule.forRoot(routes)
7.2 跳转传参 7.2.1 跳转 方式1:编程式导航 //this.$router.push() import {Router} from ‘@angular/router’
constructor(private myRouter:Router){} this.myRouter.navigateByUrl('register') 方式2: <!-- 当大家才用routerLink的方式来做页面跳转时,目的地的路由地址应该以/开头 --> <button routerLink="/register"> 没有账号?去注册 </button> 练习:(:-16:45) ①创建两个组件 demo16-list demo16-detail ②给这两个组件各自分配一个路由地址 list detail ③demo16-list 准备一个数组myList=[100,200,300] 在ul中循环的创建li,li支持以routerLink的方式跳转到detail 7.2.2 传参 list --2--》 detail 步骤1:配置接收方的路由地址 detail --> detail/:index 步骤2:发送 <any routerLink="/detail/2"></any> this.myRouter.navigateByUrl('detail/2') 步骤3:接收 //vue:this.$route.params.index import {ActivatedRoute} from '@angular/router' constructor(private myRoute:ActivatedRoute){} this.myRoute.params.subscribe((result)=>{ //result.index })7.3 路由嵌套 what? 一个路由对象,可以通过children嵌套其它的路由对象 how? 比如A,需要嵌套B\C ①给A组件先指定一个容器 ②在A组件的路由对象中 指定一个children { path:‘a’, component:A, children:[ {path:“b”,component:B}, … ] }
小案例:demo18-mail demo18-inbox demo18-outbox7.4 路由守卫 what? 路由守卫是保护一个路由对象中的组件,是否允许被访问 how? 是通过服务来实现的 ①创建一个服务 ng g service login-guard ②实现CanActivate类中的canActivate方法, 在此方法中执行一些计算,返回true/false ③调用守卫服务 找到保护的路由对象,添加一个canActivate属性
{ path:"mail", component:***, canActivate:[**,**] }接触的类/方法: import {FormsModule} from ‘@angular/forms’ import {HttpClientModule} from ‘@angular/common/http’
import {Input} from '@angular/core' import {Ontput,EventEmitter} from '@angular/core' import {HttpClient} from '@angular/common/http' import {Router} from '@angular/router' import {ActiavtedRoute} from '@angular/router'练习: ①准备两个组件demo17-list demo17-check ②各自分配一个路由地址 pList pCheck ③在demo17-list组件初始化时,向服务器发起请求http://localhost:8080/product/list,将请求到的数据保存,显示在ul的li ,li显示title (:- 10:35) ④点击li的时候,以编程式导航到pCheck,同时将此商品的lid传递过去 ⑤demo17-check接收传来的值,保存显示在h1
8、ionic 移动端开发3种形式: webApp:采用html/css/js前端技术来实现的一些移动端的网页 m.jd.com
nativeApp:采用java/kotlin/swift/oc等进行编程所生成的一些可以安装在手机操作系统的app
hybridApp:采用前端技术结合着原生的技术进行编程,生成的安装在手机OS中app
常见的基于angular的ui框架: ngzorro/GoogleMaterial/ionic…
8.1 概述 what? ionic是一个基于angular的移动端的ui组件库 并不是angular官方所提供的的 why? ①基于angular ②集成了cordova(phonegap) ③强大的cli工具 ④丰富的ui组件 when? webApp hybridApp how?
搭建环境: 官方: 步骤1: npm install -g ionic cordova 步骤2: ionic start helloWorld blank --type=ionic-angular 步骤3: cd helloWorld ionic serve 课堂: ①解压缩C:\xampp\htdocs\codes\forStu\ng\ionic_资料.zip 到当前文件夹 ②拷贝C:\xampp\htdocs\codes\forStu\ng\ionic模板myProject.zip 粘贴到C:\xampp\htdocs\codes\ionic ③解压缩C:\xampp\htdocs\codes\ionic\myProject.zip到当前文件夹 ④通过vscode打开C:\xampp\htdocs\codes\ionic\myProject文件夹,启动内置终端:npm start ⑤检查ionic是否可用 中心有外网: npm install -g ionic@3.20.0 中心没有外网: ①找到C:\xampp\htdocs\codes\forStu\ng\ionic模板\ionic_cmd.zip ②ionic_cmd.zip解压缩到当前文件夹 ③将C:\xampp\htdocs\codes\forStu\ng\ionic模板\node_modules\.bin添加到环境变量中 工作方式: 基于angular的模块,该模块中包含了很多好看的易用的移动端的ui组件 ionic = angular+ionicModule+icons+cordova npm start怎么启动? 根模块--》根组件(app.component.ts)-->在根组件中有一个变量rootPage 指向了HomePage怎么完成一个页面类的创建和调用? 创建:ionic g page demo01 调用: ①到根模块中声明 import {Demo01Page} from ‘…/pages/demo01/demo01’ @NgModule({ declarations:[Demo01Page], entryComponent:[Demo01Page] }) ②到根组件中调用 import {Demo01Page} from ‘…/pages/demo01/demo01’ rootPage:any = Demo01Page
8.2 ionic常见组件 1、button <button ion-button color=“primary/secondary/danger/light/dark” clear/outline block round>
练习:(:- 16:40) ①创建一个demo02-lianxi的页面 ionic g page **** ②先到根模块中声明,在根组件中调用 默认显示demo02-lianxi ③在demo02-lianxi的html中显示一个按钮(红色 块级显示 圆角)
2、list 常见写法: 方式1:普通文本列表 商品1 方式2:icon列表 <ion-icon item-start/end name=""> 商品1 方式3:avatar列表 <ion-avatar item-start/end > 商品1 方式4:thumbnail列表 <ion-thumbnail item-start/end > 商品1
侧滑动 <ion-list> <ion-item-sliding> <ion-item></ion-item> <ion-item-options side="left"> </ion-item-options> </ion-item-sliding> </ion-list> 下拉刷新(第一个,ionRefresh,complete) 步骤1:在ionContent的第一个子元素的调用了 <ion-refresher></ion-refresher> 步骤2:绑定ionRefresh事件 <ion-refresher (ionRefresh)="handleRefresh($event)"></ion-refresher> 步骤3:在事件处理函数中,在数据操作完成之后,结束刷新的动画效果 handleRefresh(myRefresher){ //数据操作完 //结束刷新的动画效果 myRefresher.complete() } 上拉加载更多(最后一个,ionInfinite,complete) 步骤1:在ionContent的最后一个子元素的位置调用 <ion-infinite-scroll></ion-infinite-scroll> 步骤2:绑定一个事件ionInfinite <ion-infinite-scroll (ionInfinite)="loadMore($event)"></ion-infinite-scroll> 步骤3:在事件处理函数中,当数据操作完成之后,结束动画效果 loadMore(myInfinite){ //数据操作完 myInfinite.complete() } ion-item text-wrap//换行显示item中所有的内容 (https://ionicframework.com/docs/v3/components) 练习: ①完成demo04-lianxi这个page的创建、声明、调用 ②demo04-lianxi模板 在demo04的组件类中 准备一个数组myList=[100,200,300] 将数组中的数据 显示在ionList中的ionItem;列表支持左滑动,显示一个隐藏的红色按钮(删除);点击删除,将此ionItem从ionList中移除3、grid ionic支持grid系统(基本原理:flexbox)
基础用法: <ion-grid> <ion-row> <ion-col></ion-col> ... </ion-row> ... </ion-grid> 常见的属性: ion-col:col-* offset-* push-* pull-* ion-row: align-items-start/center/end justify-content-start/center/end 练习: ①完成demo07-lianxi的页面的创建、声明、调用 ②在demo07-lianxi的html实现一个自定义的栅格布局 一行两列:最左边(免费注册) 最右边(忘记密码)4、常见窗口(alert/toast/loading/modal/actionsheet) toast:ToastController 负责用户在执行了一个操作之后,做一个结果的通知 message duration showCloseButton closeButtonText
actionsheet:ActionSheetController 交互表 负责让用户从多个选项中做选择 title buttons:[{text:'',handler:()=>{}}] loading:LoadingController 加载中,负责通知用户正在做某件事情 content duration alert: AlertController 警告、确认、输入提示 title message buttons inputs modal:ModalController 自定义的模态窗口 注意:模态窗口在调用create方法来创建的时候,第一个参数是模态窗口内部要展示的组件 如何关闭模态窗口? import {ViewController} from 'ionic-angular' constructor(private viewCtrl:ViewController){} this.viewCtrl.dismiss()5、轮播图(ionSlides) …
注意: 如果轮播图背后的数据 是动态生成的,那么当背后的数组为空,不要显示 比如: <ion-slides *ngIf="myList.length>0"></ion-slides>6、支持滚动的容器
注意: ①如果设置了允许横向滚动,那么并不是意味着现在就可以横向滚动 ②一个横向滚动 <ion-scroll style="height:200px;white-space:nowrap" scrollX> <ion-card *ngFor="let tmp of myList" style="display:inline-block"></ion-card> </ion-scroll> <ion-scroll style="height:200px" scrollY> <ion-card *ngFor="let tmp of myList"></ion-card> </ion-scroll>7、tabs tabs叫做选项卡、标签页
<ion-tabs> <ion-tab [root]="***" tabIcon="" tabTitle=""></ion-tab> <ion-tab root=""></ion-tab> <ion-tab root=""></ion-tab> </ion-tabs>8.其它 fab floating action button 悬浮式操作按钮,可以滚动在页面的某一个位置 <ion-fab right/left/center bottom/top/middle>
card 卡片是为了更好的组织一些信息 <ion-card> <ion-card-header></ion-card-header> <ion-card-content></ion-card-content> </ion-card> 表单 ionic处理表单:ionic中的表单是通过ionList和ionItem来进行管理 <ion-list> <ion-item> <ion-label floating/stacked></ion-label> <ion-input></ion-input> </ion-item> <ion-item></ion-item> </ion-list>练习: ①完成demo11-lianxi 页面的创建、声明、调用 ②实现一个按钮(验证手机号) 点击按钮–》输入提示窗口(AlertController 显示一个title/input/2个按钮ok/cancel) 点击输入提示窗口的ok按钮,显示一个toast(验证码已经发送到****)
8.3 ionic自带的路由处理 跳转: this.navCtrl.push(Demo13DetailPage)
<any [navPush]="myPage"></any> 传参: 发送: this.navCtrl .push(Demo13DetailPage,{id:10}) this.navCtrl .push(Demo13DetailPage,{id:this.myId}) <any [navPush]="myPage" [navParams]="{id:10}"></any> <any [navPush]="myPage" [navParams]="{id:myId}"></any> 接收: this.navParams.get('id')练习: ①完成两个页面 demo14-cart demo14-submit 的创建、声明,将cart作为根组件默认要展示的页面 ②在cart准备一个按钮,点击按钮以编程式导航的方式跳转demo14-submit; 同时将一个价格500传递过去,demo14-submit接收数据显示在h1(本次交易500元钱)
8.4 ionic页面的生命周期 ionViewCanEnter/CanLeave 可以通过在方法内部指定返回值为真/假 来控制是否可以进来或者离开 ionViewWillEnter/WillLeave 允许执行多次 ionViewDidLoad/ionViewWillUnload 执行一次