初涉angular之自定义指令
1.自定义指令
import {Directive, ElementRef, HostListener} from "@angular/core";
@Directive({
selector: '[nu-input]'
})
export class InputTrimDirective {
constructor(public elementRef: ElementRef) {
}
@HostListener('keyup', ['$event.target'])
keyupFun(evt) {
if (evt.value) {
this.elementRef.nativeElement.value = evt.value.trim();
}
}
}
在app.module声明指令,在app.module的declarations中声明才能生效
import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {AppComponent} from './app.component';
import {InputTrimDirective} from "./direcitve/input-trim.directive";
@NgModule({
declarations: [
AppComponent,
InputTrimDirective
],
imports: [
BrowserModule,
FormsModule,
],
bootstrap: [AppComponent]
})
export class AppModule {
}
通过inport从core库中导入Directive,HostListener,ElementRef,Input .....的引入。
Directive
用于@Directive装饰器功能,用于定义这个class是一个指令,通过@Directive修饰这样就拥有了指令的功能,我们在元组中声明selector属性值为[input-trim],方括号的写法表示是一个属性指令 还有以下几种写法:
element-name: 使用元素名称选择
.class: 使用类名选择
[attribute]: 使用属性选择
[attribute=value]:使用属性和值选择
:not(sub_selector):只有当元素与sub_selector不匹配时才选择
selector1,selector2:选择择selector1或selector2 这里我们采用属性的方式指定选择器。
这里采用的是属性的方式指定选择器,
@Directive({
selector: '[nu-input]'
})
模板中使用,直接写 nu-input
HostListener
HostListener 是属性装饰器,用来为宿主元素添加事件监,类似于我们原生JavaScript的addEventListener。 这里我们监听了keyup事件(还可以定义原生JavaScript中的其他事件),当表单中有输入的时候我们就会调用方法,传递了一个$event对象进去,后面紧跟我们触法keyup事件的方法体
ElementRef(注意:需要在构造函数中注入进去)
用于获取获取DOM节点相关的属性
这里我们当我们在页面表单输入的时候,会调用keyupFun方法,首先判断是否有值输入,有的情况下,我们通过传递进来的evt获取表单的value值,在调用trim()方法去除空格,赋值给elementRef.nativeElement.value渲染到页面
import { Input, ElementRef, OnInit, Directive } from '@angular/core';
@Directive({
selector: '[nu-input]',
exportAs: 'nuInput',
host: {
'[class.nu-input]': 'true'
}
})
export class NuInput implements OnInit {
/**
* 通过size设置input大小,默认为small, 支持big
*/
@Input() size: String = 'small';
constructor(private _elementRef: ElementRef) {
}
ngOnInit() {
(this._elementRef.nativeElement as HTMLElement).classList.add('nu-input-' + this.size);
}
}
扩展Host
这里如果我们不采用HostListener属性装饰器来监听事件,我们可以在指令的 metadata 信息中,设定宿主元素的事件监听信息,
// 自定义class类名
host: {
'[class.nu-input]': 'true'
}
// 自定义'role-data'属性
host: {
'role-data': 'hello world'
}
// 监听事件
host: {
'(keyup)': 'keyupFun($event.target)'
}
exportAs
官方解释是说,exportAs: string:定义一个名字,用于在模板中把该指令赋值给一个变量。给的例子如下
@Directive({
selector: 'child-dir',
exportAs: 'child'
})
class ChildDir { }
@Component({
selector: 'main',
template: `<child-dir #c="child"></child-dir>`
})
class MainComponent {
}
// 这是NuToolTipDirective元件中的部分内容
@Directive({
selector: '[nu-tooltip]',
exportAs: 'nuTooltip',
host: {
'[class.nu-tooltip-open]': 'isOpen'
}
})
export class NuToolTipDirective implements AfterViewInit, OnChanges, OnInit, OnDestroy {
* @ignore 是否显示tooltip
*/
isOpen = false;
......
// 在模板中使用
// #tooltip1="nuTooltip"中,nuTooltip就是NuToolTipDirective的exportAs所定义的name,
// 代表了NuToolTip这个指令本身,button中定义#tooltip1指代nuTooltip
// isOpen是元件指令中定义的Boolen值,在模板中tooltip1.isOpen调用
<button nu-button nu-tooltip #tooltip1="nuTooltip"></button><span>{{tooltip1.isOpen}}</span>
//未指代,不能获取isOpen
<button nu-button nu-tooltip #tooltip2></button><span>{{tooltip2.isOpen}}</span>
初涉angular之组件通讯
1.子component调用父component的方法或属性值
@Input
通过按钮获得hobby name,显示在list下方。
1.home.component.html
<div class="home-list">
<table>
<tr>
<td>编号</td>
<td>爱好</td>
<td>幸福指数</td>
<td>操作</td>
</tr>
<tr *ngFor="let item of hobby; let i = index;">
<td>{{i}}</td>
<td>{{item.name}}</td>
<td>{{item.fzs}}</td>
<!--getDate()获取hobby name-->
<td><button (click)="getDate(item.name)">选择</button></td>
</tr>
</table>
<p>我选择的是:</p>
<!--调用子组件-->
<app-hobby [hobbyGetName]="hobbyName"></app-hobby>
</div>
2.home.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
public hobbyName: string; //传给子组件的值
public hobby = [
{name: 'code', fzs: '100'},
{name: 'sing', fzs: '200'},
{name: 'play', fzs: '1000'},
{name: 'sleep', fzs: '500'}
];
constructor() { }
ngOnInit() {
}
getDate(name) {
console.log(name);
//将获取的值给hobbyName 赋值
this.hobbyName = name;
}
}
3.子组件
import {Component, Input, OnInit} from '@angular/core';
@Component({
selector: 'app-hobby',
templateUrl: './hobby.component.html',
styleUrls: ['./hobby.component.css']
})
export class HobbyComponent implements OnInit {
//@Input接受父组件传过来的[值]
@Input() hobbyGetName: string;
constructor() { }
ngOnInit() {
}
}
4.显示在view中
<p>{{hobbyGetName}}</p>
2.父component调用子component的方法或属性值
@Output 父组件接收子组件的数据时,子组件暴露一个EventEmitter属性,当事件发生时,子组件利用该属性emits(向上弹射)事件。父组件绑定到这个事件属性,并在事件发生时作出回应。
hobby.component.html
<p>{{hobbyGetName}}</p>
<button (click)="Descrip()">description</button>
hobby.component.ts
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
@Component({
selector: 'app-hobby',
templateUrl: './hobby.component.html',
styleUrls: ['./hobby.component.css']
})
export class HobbyComponent implements OnInit {
@Input() hobbyGetName: string;
@Output() Detail: EventEmitter<any> = new EventEmitter();
public hobbyDetail = [
{name: 'code', description: '小辫子飞起!'},
{name: 'sing', description: '听歌要命!'},
{name: 'play', description: '莫不是怕上天?'},
{name: 'sleep', description: '君何不扶摇之上?'}
];
constructor() { }
ngOnInit() {
}
Descrip() {
console.log(this.hobbyGetName);
this.hobbyDetail.forEach((i) => {
if (this.hobbyGetName === i.name) {
this.Detail.emit(i.description);
}
});
}
}
home.component.html
<p>我选择的是:</p>
<app-hobby [hobbyGetName]="hobbyName" (Detail)="hobbyDse($event)"></app-hobby>
<p>hobby的描述: </p>
<span>{{hobbyDescription}}</span>
</div>
home.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
public hobbyDescription: string;
constructor() { }
ngOnInit() {
}
hobbyDse(e) {
console.log(e);
this.hobbyDescription = e;
}
}
3.无关联component之间的通讯
Service服务
创建一个service.ts
//命令
ng generate service 'service name'
ng generate service home
在组件通用资源中,分享的是静态资源。例如login component与nav-title component的title是一样的,共享login的title。so ,在login.service.ts中,
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class LoginService {
/*共享资源为静态值*/
//分享title值
title = 'angular';
constructor() { }
}
在nav-title.component.ts中,订阅服务
import {Component, OnInit} from '@angular/core';
//加入共享的 LoginService
import { LoginService } from '../../login/login.service';
@Component({
selector: 'app-nav-title',
templateUrl: './nav-title.component.html',
styleUrls: ['./nav-title.component.css']
})
export class NavTitleComponent implements OnInit {
public title: string;
constructor(public service: LoginService ) {//订阅service
console.log(this.service.title);
this.title = this.service.title;//赋值给nav-title的title
}
ngOnInit() {
}
}
初涉angular之路由
回忆一下Vue的路由
//在template模块中直接路由,类似a标签
<router-link :to="/prodution">......</router-link>
//在方法中条用路由
this.$router.push({path: '/login'});
在router的index.js中,
//引入依赖模块
import Vue from 'vue'
import Router from 'vue-router'
//引入页面
import login from '@/page/login/login'
Vue.use(Router)
const router = new Router({
routes: [
{
path: '/',
name: 'Index',
component: Index
},{
path:'/login',
name:'login',
component:login
}
]
})
在angular中,路由与Vue相似,但是存在很大的不同
1.在cli创建时,会提示是否需要路由。
输入y,之后会在app.modules.ts引入import { AppRoutingModule } from './app-routing.module'
2.在app-routing.module.ts中,
//模块依赖引入
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
//components
import {LoginComponent} from './login/login/login.component';
import {HomeComponent} from './home/home/home.component';
//routes
const routes: Routes = [
//定义路由跳转
{path: '', component: LoginComponent},
{path: 'home', component: HomeComponent}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
3.在component中,
<a href="#" routerLink="/user">User</a>
4.在方法中,
import {Component, OnInit, NgZone} from '@angular/core';//路由依赖
import { Router } from '@angular/router';//路由依赖
import { LoginService } from '../login.service';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
public username: string;
public password: string;
constructor(
public service: LoginService,
public ngZone: NgZone,//订阅
public router: Router,//订阅
) {
console.log(this.service.title);
}
ngOnInit() {
}
loginIn() {
if (this.username == '123' && this.password == '123') {
//成功后,跳转home主页
this.ngZone.run(() => this.router.navigate(['home'])).then();
}
}
}