Angular 8 从基础到项目实战 完整的Angular学习路径

本文深入讲解Angular框架的核心概念和技术细节,包括依赖注入、组件通信、路由管理、服务端交互及响应式编程等关键技术。

安装npm依赖包 推荐使用http

npm i --registry=http://registry.npmjs.org/

关于跨域可以使用nginx代理,关于package.json可以执行npm start,npm build…

"scripts": {
   
   
  "ng": "ng",
  "start": "ng serve",
  "start.prod": "ng serve --aot",
  "build": "ng build",
  "test": "ng test",
  "lint": "ng lint",
  "e2e": "ng e2e",
  "ivy": "ivy-ngcc"
},

注意nodejs版本、以及angular-cli版本

ng --version 查看是否安装成功

ng new taskAngular 生成项目cli

ng serve --host 0.0.0.0 保证项目和手机使用相同的网络 可以真机调试

  1. ng new xxx 创建一个项目
  2. 重新安装依赖 要先把原来的删除
  3. .gitignore git提交忽略的文件
  4. .editorconfig 编辑器
  5. browserslist 兼容浏览器
  6. karma.conf.js 测试配置
  7. package-lock.json package 里面的包 依赖的其他包 细致的罗列出来 依据package.json文件,控制依赖里面其他依赖的版本
  8. tsconfig.app.json 继承与tsconfig.json typescript 对于全局的设置
  9. tslint.json 做静态文件扫描的
  10. tsconfig.spec.json 是测试相关的配置
  11. ng lint 对项目的代码进行检查
  12. typescript 是js的高级
  13. 真机调试 ng serve --host 0.0.0.0 手机电脑 在同一个Wi-Fi环境 手机打开http://<电脑ip>:4200

在这里插入图片描述

使用vscode开启debug模式

使用svccode debugg 工具 进入菜单后 如果没有初始化 先点击设置 设置为浏览器 端口改为 项目运行的端口 前提是项目在运行中 会新开一个窗口

我当前的版本 需要先设置断点 再启动debug 就进入debug模式了

目录结构介绍

在这里插入图片描述

在这里插入图片描述


**重点理解interface interface 类型的命名,是用来规范class的 **

export interface TopMenu {
   
         // interface 做类型命名
  title: string;
  link: string;
}
interface Add {
   
   
  (x: number, y:number): number
}

interface Dict {
   
   
  [key: string]: string
}
export class ScrollableTabComponent {
   
   
  @Input() selectedTabLink: string;         // 路由切换后 页面刷新 让tab 自动选中
  @Input() menus: TopMenu[] = [];
  @Input() selectedIndex = 0;
  @Input() backgroundColor = '#fff';
  @Input() titleActiveColor = 'yellow';
  @Input() titleColor = 'blue';
  @Input() indicatorColor = 'brown';
  @Output() tabSelected = new EventEmitter();
  /**
   * 第一个执行,构造函数是建立这个类的实例
   * 之所以我们没有显性的使用 new ScrollableTabComponent()
   * 是因为系统框架帮我们做了这个,这是依赖注入的概念
   */
  constructor() {
   
   
    console.log('构造函数');
    console.log(this.dict.a)
  }
  AddFunc: Add = (x, y) => {
   
   
    return x+y
  }

  dict: Dict = {
   
   
    a: '1',
    b: '2'
  } 

  handleSelection(index: number) {
   
   
    this.tabSelected.emit(this.menus[index]);
  }
}

使用下面的命令可以快速生成模块文件

在这里插入图片描述

常用的指令

在这里插入图片描述

<ul [ngStyle]="{ 'background-color': backgroundColor }">
  <!-- 指令 ngFor ngStyle ngClass (click) -->
  
  <!-- [class.active]=" i=== 1"   单个样式条件绑定比较合适-->

  <!-- [ngClass] [ngStyle] -->

  <!-- trackBy 相当于vue的key -->
  
   <!-- ngIf 和 else的 写法 -->
  <!-- *ngIf="menu.link === selectedTabLink"
      else eleTem -->
  <!--   <ng-template #eleTem></ng-template> -->
  
  <li
    *ngFor="let menu of menus; let i = index; let even = even; let odd = odd"
    [ngClass]="{ even: even, odd: odd }"
  >
    <a
      [ngStyle]="{ color: i === selectedIndex ? titleActiveColor : titleColor }"
      (click)="handleSelection(i)"
    >
      {
   
   {
   
    menu.title }}
    </a>
    <span
      class="indicator"
      [ngStyle]="{ 'background-color': indicatorColor }"
      *ngIf="menu.link === selectedTabLink"
    ></span>
  </li>
</ul>
<ng-content></ng-content>
// 结构指令 ngIf ngFor ngSwitch
// 属性指令 ngClass ngStyle ngModel

在这里插入图片描述

  • ngStyle
  • ngClass
  • ngFor 注意里面获取值的方法 trackBy 根据某个值渲染排序
  • ngIf
  • click事件绑定
  • ngModel

在这里插入图片描述
在这里插入图片描述

<!-- 双向数据绑定 的模版  双向绑定的概念 -->
<input [value]="username" (input)="username = $event.target.value">
<input [(ngModel)]='username'>
<p>
  <input type="text" [name]='name' (input)= "name = $event.target.value">
  <span>您好 {
  
  {name}}</span>

  <input type="text" [(ngModel)]= "name">
  <span>您好 {
  
  {name}}</span>
</p>

angular生命周期

在这里插入图片描述
生命周期

// 生命周期
// constructor 构造函数 永远首先被调用
// ngOnChanges 输入属性变化时被调用  @input 发生变化时触发
// ngOnInit  组件初始化时被调用   只执行一次
// ngDoCheck 脏值检测时调用  

// ngAfterContentInit  当投影内容ng-content 当组件中子组件初始化 完成时调用 
// ngAfterContentChecked  当检测组件中子组件 多次调用
// ngAfterViewInit 当组件包含自己 以及子组件(整体视图) 初始化完成
// ngAfterViewChecked 组件整体视图的 脏值检测

// ngOnDestroy  组件销毁  做一些清除工作

@Component({ // @Component 装饰器 也叫注解 其实就是一个函数 一个返回函数的函数
1、selector: ‘app-root’, // 选择器 找到html的标签
2、 templateUrl: ‘./app.component.html’, // 模版的路径
3、styleUrls: [‘./app.component.css’] // 是个数组 可以有多个文件

import {
   
    Component, OnInit, Input, Output, EventEmitter } from '@angular/core';


export interface TopMenu {
   
         // interface 做类型命名
  title: string;
  link: string;
}

@Component({
   
   
  selector: 'app-scroll-top-menu',
  templateUrl: './scroll-top-menu.component.html',
  styleUrls: ['./scroll-top-menu.component.scss']
})
export class ScrollTopMenuComponent implements OnInit {
   
   
  title = '';
  selected = -1;
  // 数据注入 事件监听 例如vue的 prop emit
  @Input() menus: TopMenu[] = [];
  @Input() backgroundC = ''
  @Input() active = ''
  @Output() tabClickEvent = new EventEmitter();
  handlselect(index: number) {
   
   
    this.selected = index;
    this.tabClickEvent.emit(this.menus[this.selected])
  }
  constructor() {
   
    
    // 构造函数 永远首先被调用
    console.log('组件构造调用')
  }
  ngOnChanges(changes) {
   
   
    // 输入属性变化时 调用
    console.log(changes);
  }
  ngOnInit() {
   
   
    // 组件初始化
    console.log('组件初始化')
  }
  ngDoCheck() {
   
   
    // 脏值检测调用
  }
  ngOnDestroy() {
   
   
    // 组件销毁时 调用
  }
  
  ngAfterContentInit() {
   
   
    // 组件内容初始化
  }

  ngAfterViewInit() {
   
   
    // 组件子组件初始化
  }

}

父子组件通信 类似vue(v-model双向绑定)

父组件通过@Input向子组件传递数据 子组件通过@Output()向外传递

可以全局搜索@Input、@Output查看应用实例


装饰器(注解)

其实就是一个 返回函数的 函数 return了一个函数 他是typescript 的特性 而非angular的特性

/Users/niko4/Desktop/pinduoduo/src/app/shared/decorators/index.ts 在share目录下 新建 decorators文件夹


export function Emoji() {
   
   
    // 返回一个匿名函数的 es6的写法
    return (target: object, key: string) => {
   
   
        let val = target[key] // 原来的值 =》 一个属性

        const getter = () => {
   
   
            return val;
        } 

        const setter = (value: string) => {
   
   
            val =  `😄 ${
     
     value}}`
        }

        Object.defineProperty(target, key, {
   
   
            set: setter,
            get: getter,
            enumerable: true,
            configurable: true
        })
    }
}

export function confimable(message: string) {
   
   
    return (target: object, key: string, descriptor: PropertyDescriptor) =>{
   
   
        const original = descriptor.value; // 原来的值 =》 一个函数
        descriptor.value = function (...args: any) {
   
   
            const allow = window.confirm(message)
            if (allow) {
   
   
                const result = original.apply(this, args)
                return result
            } else {
   
   
                return null;
            }
        }
        return descriptor;
    }
}

如何使用:@Emoji() result = ‘hello’ 在模版中绑定{ {result}}


app.module.ts 详细介绍

注意下面的注释

import {
   
    BrowserModule } from '@angular/platform-browser';
import {
   
    NgModule } from '@angular/core';

import {
   
    AppComponent } from './app.component';
import {
   
    FormsModule } from '@angular/forms';
import {
   
    ShareModule } from './share/share.module';

@NgModule({
   
     //  @NgModule 注解
  declarations: [  // 当前模块拥有的组件 有哪些组件属于我这个模块
    AppComponent,
  ],
  imports: [   // 引入当前模块需要的依赖   // 依赖于那些组件
    BrowserModule,
    FormsModule,
    ShareModule
  ],
  providers: [],  // 模块中需要使用的服务
  bootstrap: [AppComponent]  // 根模块 只有根模块有这个  第一个展示什么组件 也叫引导组件
})
export class AppModule {
   
    }

自定义指令

模版也是一种指令

/Users/niko4/Desktop/pinduoduo/src/app/shared/directives 用指令的方法创建模版

  • 指令 没有模版,它需要一个宿主(host)元素 寄宿到他的身上。
  • 推荐使用方括号 [] 指定 Selector,使它变成一个属性。
import {
   
    Directive, ElementRef, HostBinding, HostListener, Input, Renderer2 } from "@angular/core";

@Directive({
   
   
    selector: '[keepImg]'   //选择器 用来规定绑定到那里
})

export class HoriGridImageDirective {
   
   
    @Input() keepImg = '2rem';
    constructor(private elr: ElementRef, private rd2 : Renderer2) {
   
   
        
    }
    // 指令绑定样式 的 第二种写法
    @HostBinding('style.width') width = this.keepImg
    @HostBinding('style.grid-area') area = 'images'
    @HostBinding('style.height') height = this.keepImg
    ngOnInit() {
   
   
        // this.rd2.setStyle(this.elr.nativeElement, 'grid-area', 'images');
        // this.rd2.setStyle(this.elr.nativeElement, 'width', this.keepImg);
        // this.rd2.setStyle(this.elr.nativeElement, 'height', this.keepImg);
    }
	指令的 事件绑定
    @HostListener('click', ['$event.target'])
    handleClick(ev) {
   
   
        console.log(ev);
    }
}
<div keep *ngFor="let item of channls">
    <img [keepImg]= "'4rem'" [src]="item.icon" [alt]="item.caption">
    <span keepTitle>{
  
  {item.title}}</span>
  </div>

ng-content 组件内容投射 可以理解为vue插槽但又有所不同

结合自定指令很好的解决了多级父子孙组件数据和事件传递的且套问题

动态组件 ng-content 增加select 属性 限制要显示的内容

src/app/share/components/hori-grid/hori-grid.component.html

<!-- select 可以选择css 或者是dom元素 去控制显示 -->
<div class="contanier">
  <ng-content></ng-content>
</div>

src/app/app.component.html

<app-hori-grid>
  <div keep *ngFor="let item of channls">
    <img [keepImg]= "'4rem'" [src]="item.icon" [alt]="item.caption">
    <span keepTitle>{
  
  {item.title}}</span>
  </div>
</app-hori-grid>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

如何操作dom

src/app/share/components/image-slider/image-slider.component.html

  <div class="container">
    <div class="image-slider" #imageSliderID>
      <img #img *ngFor="let item of sliders" [src]="item.imgUrl" [alt]="item.caption">
    </div>
    <div class="navsection">
      <span *ngFor="let items of sliders" class="slider-button"></span>
    </div>
  </div>

注意下#开头的ID

src/app/share/components/image-slider/image-slider.component.ts

import {
   
    Component, ElementRef, Input, OnInit, QueryList, Renderer2, ViewChild, ViewChildren } from '@angular/core';

export interface ImageSlider {
   
   
  imgUrl: string,
  link: string,
  caption: string
}

@Component({
   
   
  selector: 'app-image-slider',
  templateUrl: './image-slider.component.html',
  styleUrls: ['./image-slider.component.scss']
})
export class ImageSliderComponent implements OnInit {
   
   
  @Input() sliders: ImageSlider[] = []
  // 如果组件在 if判断中 static 就是false 否则就是 true
  @Input() IntervalBySeconds = 2
  @ViewChild('imageSliderID', {
   
    static: true }) imageSliderID: ElementRef
  @ViewChildren('img') imgs: QueryList <ElementRef>
  constructor(private rd2: Renderer2) {
   
    }

  ngOnInit() {
   
   
    console.log(this.imageSliderID
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值