zoukankan      html  css  js  c++  java
  • Angular

    1、数据绑定的四种形式:

    (1)插值    <p>{{title}}</p>

    (2)属性绑定     <img [src]="userUrl"/>

    (3)事件绑定     <button (click)='onSave()'>点击</button>

    (4)双向绑定     <input [(ngModel)]='title'/>

            在双向绑定中,数据属性值通过属性绑定从组件流到输入框,当修改输入框内容时通过事件绑定流回组件,把属性值设为最新值。

    选择属性绑定还是插值?

      当渲染的数据类型是字符串时,倾向于可读性更好的插值;但是当数据类型不是字符串时,必须用属性绑定了。

    属性绑定与attribute绑定的区别?

      用属性绑定来设置元素的属性总是好于用字符串设置attribute,但是当元素没有属性可绑时,就必须用attribute绑定。

           如:  colspan不是td的属性

    <tr><td [attr.colspan]="1+1">One-Two</td></tr>

    CSS类绑定

    • 全有或全无的替换型绑定

       <div class='bad curly special' [class]='isTrue'></div>

    • 绑定到特定类名    单个class的添加与移除

       <div [class.special]='isTrue'></div>

               同时添加或移除多个class

         <div [ngClass]="{'background':isBg,'fontColor':isFontColor}"></div>

    样式绑定

    • 单个样式绑定   <button [style.color]="isSpecial?'red':'green'"></button>

    2、指令

    (1)结构型指令:通过添加、移除或替换DOM来修改布局。如 *ngIf、*ngFor

    (2)属性型指令:会修改现有元素的外观或行为。 如 NgClass、NgStyle、NgModel

    2.1、为什么要给结构型指令加上“*”?

      星号是用来简化更复杂语法的“语法糖”,从内部实现来说,Angular把*ngIf属性翻译成了一个<ng-template>元素,并用它来包裹宿主元素

       如<div *ngIf="hero">hero</div>  =======》

        <ng-template [ngIf]="hero">
          <div>hero</div>
        </ng-template>

    2.2、*ngIf有else

    <div *ngIf="display else noData"></div>
    <ng-template #noData></ng-template>

    在Angular中一个标签上不能同时使用两个指令,可以通过在外层添加一个<ng-container>来解决

    2.3、<ng-container> VS<ng-template> VS <ng-content>

    <ng-container>渲染所包含的模板内容,不包含自身

    <div>
        <ng-container>
            <span>Hello World!</span>
        </ng-container>
    </div>
    
    <!-- 实际渲染结果是 -->
    <div>
        <span>Hello World!</span>
    </div>

    <ng-template>它不会直接渲染任何内容,主要是配合其他的结构型指令一起使用

    <ng-template>
        <span>Hello World!</span>
    </ng-template>
    
    <!-- 默认不会渲染任何内容 -->

    <ng-content>使得这个组件能接收外部投射进来的内容,也就是说组件最终呈现的内容不仅仅是本身定义的那些。

    父组件在调用子组件时,还可以在子组件里添加内容,然后在子组件中使用<ng-content>显示那部分内容到该处。

    //父组件中调用子组件 app-with-title
    <app-with-title>
        <div>hello</div>
        <div>world</div>
    </app-with-title>
    //子组件
    <div>title</div>
    <ng-content></ng-content>
    
    // 子组件实际渲染的结果是
    <div>title</div>
    <div>hello</div>
    <div>world</div>

    2.4、ng-container 只会展示包含的内容

    下面的实例,很好的展示了 ng-container 的用法;需求是只展示奇数的数据,如果是同时使用 ngFor 和 ngIf 会报错

    <ul>
        <li *ngFor="let item of list; let odd = odd" * ngIf="odd">
            {{ item }}
        </li>
    </ul>

    会报错,*开头的指令,一个元素只能使用一次

    <ul>
        <ng-container *ngFor="let item of list; let odd = odd">
            <li *ngIf="odd">{{ item }}</li>
        </ng-container>
    </ul>

    2.5、*ngTemplateOutlet

    <ng-template #data>
        Hello World
    </ng-template>
    
    <div *ngTemplateOutlet="data"></div>

    类似 angularJS 里面的 include,加载对应的模块代码块,不过更强大,像是调用一个函数,可以传参

    在使用 *ngTemplateOutlet 的时候,可以加上 context 代表要传入 ng-template 的参数,比如

    <div *ngTemplateOutlet="data; context: {$implicit: {value: 1}}"></div>
    //这个 $implicit 是一个固定用法,就像es6 module中的export default一样, $implicit 后面的值,会被当做传入 ng-template 的默认参数
    
    //在 ng-template 里只需要使用 let-xxx 的方式,就可以接收到这个传入的默认参数
    <ng-template #data let-xxx>
      {{ xxx | json }}
    </ng-template>
    
    <div *ngTemplateOutlet="data; context: {$implicit: {value: 1}}"></div>
    //使用 let-xxx,ng-template 內部就有一个 xxx 变量,这里 xxx 的值就是 {value : 1}

    ng-template 传入多个参数

    $implicit 的方式实际上就是 let-xxx="$implicit",如果有多个参数需要传入,可以这样:

    <ng-template #data let-xxx let-another="another">
        <div>{{ xxx | json }}</div>
        <div>{{ another | json }}</div>
    </ng-template>
    
    <div
        *ngTemplateOutlet="data; context: {$implicit: {value: 1}, another: {value: 2}}"
    ></div>

    3、获取用户数据的方式:

    使用Angular的模板引用变量,这些变量提供了从模板中直接访问元素的能力,在标识符前加上井号# 就能直接声明一个模板引用变量了。

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

    //按键事件过滤
    <input #box (keyup.enter)="onEnter(box.value)"/>
    onkey(value:string){
      this.value=value;
    }

    通过$event对象取得用户输入

    <input (keyup)="onkey($event)"/>
    onkey(event:any){
        this.value=event.target.value;
    }

    但是通过$event是靠不住的做法,反对把整个dom事件传入方法中,因为这样组件会知道太多模板的信息,这样就违反了模板和组件之间的分离关注原则了。

    4、组件间的交互的方式

    (1)父---->子

    子组件若接收来自父组件传入的消息,必须定义一个输入属性,该属性通过Input装饰器修饰的。

    //子组件  child.ts
    @Input() private message:string;
    //父组件 html
    <child [message]="msgToChild"></child>

    (2)子----->父

    通过输出接口完成

    //子组件 child.ts
    @Output() private outer=new EventEmitter<string>();
    sendToParent(){
        this.outer.emit('message from child');
    }
    //父组件
    //. html
    <child (outer)="recieve($event)"></child>     
    //.ts    
    private msgFromChild:string;
    recieve($e:any){
        this.msgFromChild=$e;
    }

    (3)父子组件通过本地变量互动

    父组件不能使用数据绑定来读取子组件的属性或调用子组件的方法,但是,可以在父组件的模板中,新建一个本地变量来代表子组件,然后利用这个变量来读取子组件的属性和调用子组件的方法。

    //html文件
    <child #children></child> //子组件 <button (click)="children.start()"></button>

    (4)@viewChild()

    两种用法:1、读取子组件

    如果父组件的类需要读取子组件的值或方法,就不能使用本地变量的方法了。当父组件需要这种访问时,可以把子组件作为viewChild注入到父组件中

    //html文件
    <child></child> //子组件
    <button (click)="start()"></button>
    //ts文件
    import { child} from './components/child.component';
    @viewChild(child);
    private sonComponent:child;
    start(){
          this. sonComponent.start();
    }

    @viewChild()的另一种用法:2、获取当前组件视图的单个元素

    //.html
    <input #name/>
    //.ts
    @viewChild('name') myName:ElementRef;
    this.myName.nativeElement.focus();

     (5)同级组件间通信

    • 共用服务

      两个组件同时调用某个服务,需要发送数据的组件调用该服务的方法,需要接收该信息的组件,可以定义一个观察者对象,监听数据变化。

    • $rootscope实现作用域间通信

    5、路由

    <router-outlet></router-outlet>把要显示在这个出口处的组件显示在这里。

    路由跳转

    <a routerLink="/heroes" routerLinkActive="active">Heroes</a>
    <a routerLink="['/heroes']">Heroes</a>
    <a routerLink="[/home]"+row.id>Heroes</a>//根据id跳转
    //routerLinkActive表示当链接激活时添加“active”类
    
    this.router.navigate(['/home']);  在ts文件中

    根据参数跳转路由:

    {
        path:'home/:id',
        component:HomeComponent    
    }
    //获取参数id
    //(1)
    constructor(private route:ActivatedRoute){
       route.params.subscribe(params=>{this.id=params['id']})
    }
    //(2)
    constructor(private route:ActivatedRoute){}
    const id=this.route.snapshot.paramMap.get('id');

    6、管道

    把数据作为输入,然后转换它,给出期望的输出。

    <p>Hero`s birthdat is {{birthday | date}}</p>

    让组件的birthday值通过管道操作符(|)流动到右侧的date管道函数中,所有管道都会用这种方式工作。

    7、服务与依赖注入

    为什么要用服务?

    通常需要对访问的数据做后处理、添加错误处理器,还可能加一些重试逻辑,以便应对网络问题。如果直接写在组件中,会因为这些数据方式的细节而变得杂乱不堪,组件变得难以理解,难以测试,并且这些数据访问逻辑无法被复用,也无法标准化,所以把数据展示逻辑与数据访问逻辑分开。

    Angular把组件与服务区分开,以提高模块性和复用性。通过把组件中和视图相关的功能与其他类型的处理分离开,可以使组件类更精简、高效。

    组件应该把诸如从服务器获取数据、验证用户输入等工作委托给服务。

    依赖注入:是组件引入外部构建(如服务)的一种机制。

    8、Angular双向绑定实现原理

    Angular在scope模型上设置了一个监听队列,用来监听数据变化并更新视图。每次绑定一个数据或事件时angular就会往$watch队列中插入一条$watch,用来检测它监听的模型里是否有变化的内容。当浏览器接收到可以被Angular context处理的事件时,就会触发$digest循环,遍历所有的$watch检查其属性和值是否发生变化, 最后更新DOM。

    实现方法:

    (1)每个双向绑定的元素都有一个watcher;

    (2)在某些事件发生时,调用digest对脏数据进行检测,这些事件有表单内容发生变化、Ajax请求响应、单击按钮执行回调函数等。

    (3)脏数据检测,会检测到rootscope下所有被watcher监控的元素。 $digest函数就是脏数据检测函数。

    如:

    • 当我们点击按钮时,浏览器接收一个事件,进入angular context。
    • $digest循坏开始执行,查询每个$watch是否变化。
    • 由于监听$scope.name的$watch报告了变化,他会强制再执行一次$digest循环。
    • 新的$digest循环没有检测到变化。
    • 更新与$digest.name 新值相应部分的DOM。

    9、Angular生命周期

    (1)ngOnChanges:当数据绑定输入属性的值发生变化时调用,初始化前也会被调用一次。

    (2)ngOnInit:初始化

    (3)ngDoCheck:自定义的方法,用于检测和处理值的改变

    (4)ngAfterContentInit:在组件内容初始化之后调用

    (5)ngAfterContentChecked:组件每次检查内容时更新

    (6)ngAfterViewInit:组件相应的视图初始化之后调用

    (7)ngAfterViewChecked:组件每次检查视图时调用

    (8)ngOnDestory:指令销毁前调用。

    10、ng-if与ng-show的区别

    (1)ng-if在表达式为true的时候才会创建这个dom节点,ng-show是初始时就创建了,只用用display来控制显示与隐藏。

    (2)ng-if会(隐式地)产生新作用域,ng-switch、ng-include等会动态创建一块界面的也是如此。

    这样会导致在ng-if中用基本变量绑定ng-model,在外层div中把此model绑定给另一个显示区域,内层改变时,外层不会同步改变,因为此时已经是两个变量了。

           

      ng-show不存在这个问题,因为它不自带一级作用域。

      避免这一问题出现的方法是:始终将页面中的元素绑定到对象的属性(data.x)上,而不是直接绑定到基本变量(x)上。

  • 相关阅读:
    摄像机模型 (Camera Model)
    TP中如何用IF
    Mysql连接报错:1130-host ... is not allowed to connect to this MySql server如何处理
    LNMP环境源码搭建
    Linux之不得不说的init(Linux启动级别的含义 init 0-6)
    PHP 生成毫秒时间戳
    Linux Bash Shell字符串截取
    Linux crontab任务调度
    下载百度文库文档
    关于java socket中的read方法阻塞问题
  • 原文地址:https://www.cnblogs.com/xiaoan0705/p/11137178.html
Copyright © 2011-2022 走看看