迈向angularjs2系列(2):angular2指令详解
目录
1.hello world!
2.配置开发环境
源代码下载
链接: https://pan.baidu.com/s/1i5pGloT 密码: g7ub
一:helloworld!
注意:这一小节的内容,并非生产环境的做法,读者可以不必操作,看演示就好了。
为了简单快速的运行ng2程序,那么引入直接angular2版本和页面的基本框架。
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<app></app>
<!--使用app组件-->
<script src="https://code.angularjs.org/2.0.0-beta.9/angular2-polyfills.min.js"> </script>
<script src="https://code.angularjs.org/2.0.0-beta.9/Rx.umd.min.js"> </script>
<script src="https://code.angularjs.org/2.0.0-beta.9/angular2-all.umd.min.js"> </script>
<script src="./app.js"></script> </body>
</html>
app.js:
var App=ng.core.Component({
//定义了名称为App的组件。
selector:"app",
//匹配所有的app标签
template:"<h1>hello {{target}}</h1>"
})
.Class({
//Class函数传递了一个对象字面量,只有constuctor方法
constructor:function(){
this.target="world";
}
});
ng.platform.browser.bootstrap(App);
//ng.platform.browser是命名空间
直接打开index.html,那么html显示为:
结论:并没有用到typescript,所以它不是必须的,但ng2强烈推荐使用。
二: 配置开发环境和angular2的typescript实现
1.通过git克隆项目
step1:安装git
到网站下载exe文件,https://github.com/git-for-windows/git/releases/download/v2.13.2.windows.1/Git-2.13.2-64-bit.exe。安装的过程我只是改了一下安装目录。
安装目录:
检测git是否安装正确:
首先在开始菜单里找到git cmd(也可以吧快捷方式发送到桌面),然后输出命令git --version。
step2:进入自己的项目目录,运行命令 git clone https://github.com/mgechev/switching-to-angular2.git 。
已经克隆下来。good!
step3:进入项目目录,模块安装,然后启动Server。
$ npm install ;
$ npm start;//启动server
浏览器显示结果为:
success!
step4:上手试玩(optional)
内容替换,switching-to-angular2/app/ch4/ts/hello-world/app.ts:
import {Component} from '@angular/core';
import {bootstrap} from '@angular/platform-browser-dynamic'; @Component({
selector: 'app',
templateUrl: './app.html'
})
class App {
target:string;
constructor() {
this.target = 'world';
}
} bootstrap(App);
浏览器显示结果为:
2.hello-world深度解析
注意:代码位于switching-to-angular2/app/ch4/ts/hello-world目录)
首先,看一下一共有4个文件。
index.html负责hello-world的首页(默认)文件的显示,app.html负责app模板的内容,meta.json是一些元信息,app.ts负责js代码逻辑。
接下来详细看index.html。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title><%= TITLE %></title>
<!--TITLE变量注入-->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- inject:css -->
<!-- endinject -->
</head>
<body> <app>Loading...</app>
<!--app组件-->
<!-- inject:js -->
<!-- endinject -->
<%= INIT %>
<!--INIT是变量注入-->
</body>
</html>
app标签有文本内容,"Loading"一直处于可见状态,直到应用启动好、主组件渲染完毕为止。而 <%= TITLE %> 和 <%= INIT %> 是用来注入变量的。这些变量是在哪里定义的呢?
另,传授一个全局搜索文本的方法:
step1:文件目录右键,选择find in path
step2:搜索"TITLE"。
所以,它的定义在switching-to-angular2/tools/tasks的build.index.ts文件中。
build.index.ts:
import {join, sep} from 'path';
import {APP_SRC, APP_DEST, DEPENDENCIES, SYSTEM_CONFIG, ENV} from '../config';
import {transformPath, templateLocals} from '../utils'; export = function buildIndexDev(gulp, plugins) {
return function () {
return gulp.src(join(APP_SRC, '**', 'index.html'))
// NOTE: There might be a way to pipe in loop.
.pipe(inject())
.pipe(plugins.template(
require('merge')(templateLocals(), {
TITLE: 'Switching to Angular 2',
INIT: `
<script>
System.config(${JSON.stringify(SYSTEM_CONFIG)});
System.import("./app")
.catch(function () {
console.log("Report this error to https://github.com/mgechev/switching-to-angular2/issues", e);
});
</script>`
})
))
.pipe(gulp.dest(APP_DEST));
}; function inject() {
return plugins.inject(gulp.src(getInjectablesDependenciesRef(), { read: false }), {
transform: transformPath(plugins, 'dev')
});
} function getInjectablesDependenciesRef() {
let shims = DEPENDENCIES.filter(dep => dep['inject'] && dep['inject'] === 'shims');
let libs = DEPENDENCIES.filter(dep => dep['inject'] && dep['inject'] === 'libs');
let all = DEPENDENCIES.filter(dep => dep['inject'] && dep['inject'] === true);
return shims.concat(libs).concat(all).map(mapPath);
} function mapPath(dep) {
let prodPath = join(dep.dest, dep.src.split(sep).pop());
return ('prod' === ENV ? prodPath : dep.src );
}
};
build.index.ts
第三,分析一下ch4/ts/hello-world/app.ts。
import {Component} from '@angular/core';
//导入了component装饰器
import {bootstrap} from '@angular/platform-browser-dynamic';
//导入了bootstrap函数
@Component({
//Component装饰了class App
selector: 'app',
templateUrl: './app.html'
//对象字面量参数和ES5类似,app选择器和视图内容。模板既可以template内联,也可以使用url,和ng1类似。
})
class App {
target:string;
constructor() {
this.target = 'world';
}
}
bootstrap(App);
//启动APP
四: angular2指令详解
开发app组件现在开始了!
1.基础to-do list应用
(1)运行代码:
进入switchingToNG2/switching-to-angular2目录,运行npm start,那么打开浏览器,进入红色框的链接。
(2)进入switching-to-angular2/app/ch4/ts/ng-for/detailed-syntax目录,一共4个部分。
app.ts:
import {Component} from '@angular/core';
import {bootstrap} from '@angular/platform-browser-dynamic';
//导入
@Component({
//装饰器
selector: 'app',
templateUrl: './app.html',
})
class App {
todos:string[];
name:string;
constructor() {
//app类的属性定义,可以直接在app组件的代码里使用
this.name = "爱莎";
this.todos = ['呼风唤雪', "保护妹妹"];
}
} bootstrap(App);
//启动应用
app.html:
<h1>你好,{{name}}!</h1>
<h3>
to-do清单:
</h3>
<ul>
<template ngFor let-todo [ngForOf]="todos">
<li>{{todo}}</li>
</template>
</ul>
说明:template标签内部可以放HTML片段。template的作用是屏蔽了浏览器的直接渲染,交给模板引擎来处理。
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title><%= TITLE %></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- inject:css -->
<!-- endinject -->
</head>
<body> <app>Loading...</app>
<!-- inject:js -->
<!-- endinject -->
<%= INIT %>
</body>
</html>
默认页面类似之前DEMO的内容
meta.json:
{
"title": "List of items (detailed syntax)",
"description": "List of items using explicit template for ng-for",
"id": ,
"presented": true
}
这里的title在index.html中有使用到。
(3)结果显示。
打开http://localhost:5555/dist/dev/ch4/ts/ng-for/detailed-syntax/地址,显示如下:
2. 更加优秀的ngFor指令
ngFor用来遍历数据,和ng1的ng-repeat类似,也更优秀。
<template ngFor let-todo [ngForOf]="todos">
<li>{{todo}}</li>
</template>
ng1的指令用法五花八门,需要对各种属性值深入去理解。而ng2引入了更加简单的约定,语义性更高。
属性有3种用法:
●propertyName="value"
第一种语法:普通字面量
propertyName接收字符串字面量,要使用引号哦。angular不会对它进行进一步处理。
●[propertyName]="expression"
第二种语法:方括号语法
提示angular2要当做表达式来处理。属性包围在方括号里面,angular就会尝试执行这个表达式,执行上下文就是模板对应的组件。
●(eventName)="handlerFunc()"
第三种语法:小括号语法
当然是事件绑定咯。
:) 可以看到,谁是谁,非常清晰。
(1)模板如何使用ngFor指令
<template ngFor let-todo [ngForOf]="todos"> [ngForOf]是遍历的数据集合,let-todo(这里是var-变量名语法)告诉ng2遍历创建的新变量名字叫todo,类型是let。
(2)使用语法糖
语法糖,简单的说就是更方便更简洁的写法。
使用星号,扔掉template标签 ,指令也直接用到容器标签上。
<ul>
<li *ngFor="#todo of todos">{{todo}}</li>
</ul>
angular2会自动对上面代码进行“脱糖”处理,就能变成上面比较啰嗦的形式了。
3.自定义angular2指令
上一节讲了如何在DOM标签上使用内置指令,这一节讲自定义指令。自定义才是高级玩法。
本小节将构建一个简单的tooltip自定义指令。
(1)运行代码:
进入switchingToNG2/switching-to-angular2目录,运行npm start,那么打开浏览器,进入红色框的链接。
(2)进入目录switching-to-angular2/app/ch4/ts/tooltip,
app.html:
<div saTooltip="Hello world!">
</div>
ch4/ts/tooltip/app.ts:
一共分为导入、Overlay类、指令、常规的APP类定义。
//导入
import {HostListener, Input, Injectable, ElementRef, Inject, Directive, Component} from '@angular/core'; import {bootstrap} from '@angular/platform-browser-dynamic'; //Overlay类的定义
class Overlay {
private el: HTMLElement;
constructor() {
var el = document.createElement('div');
el.className = 'tooltip';
this.el = el;
}
close() {
this.el.hidden = true;
}
open(el, text) {
this.el.innerHTML = text;
this.el.hidden = false;
var rect = el.nativeElement.getBoundingClientRect();
this.el.style.left = rect.left + 'px';
this.el.style.top = rect.top + 'px';
}
attach(target) {
target.appendChild(this.el);
}
detach() {
this.el.parentNode.removeChild(this.el);
}
}
//指令定义
@Directive({
selector: '[saTooltip]'
})
export class Tooltip {
@Input()
saTooltip:string; constructor(private el: ElementRef, private overlay: Overlay) {
this.overlay.attach(el.nativeElement);
}
@HostListener('mouseenter')
onMouseEnter() {
this.overlay.open(this.el, this.saTooltip);
}
@HostListener('mouseleave')
onMouseLeave() {
this.overlay.close();
}
}
//APP类定义,并被component装饰器修饰以及最后的启动
@Component({
selector: 'app',
templateUrl: './app.html',
providers: [Overlay],
directives: [Tooltip]
}) class App {} bootstrap(App);
(3)结果显示。
打开http://localhost:5555/dist/dev/ch4/ts/tooltip/地址,那么会有如下结果:
(2)导入的类HostListener、Directive、ElementRef
app.ts导入了HostListener, Input, Injectable, ElementRef, Inject, Directive, Component这些类。
●HostListener(eventname)
用于事件处理。指令实例化的时候,angular2会把这个装饰过的方法当成宿主标签上对应eventname的事件处理函数。
@HostListener('mouseenter')
//定义监听器
onMouseEnter() {
this.overlay.open(this.el, this.saTooltip);
}
//定义监听函数
●Directive
用于定义指令。用来添加额外的元数据。
//指令定义
@Directive({
selector: '[saTooltip]'
//大小写敏感哦
})
●ElementRef
在宿主标签里注入其他标签的引用,不仅仅是DOM。比如这里的模板就是angular包装过的div标签,里面有tooltip属性。
<div saTooltip="Hello world!">
</div>
(3)指令输入的input装饰器
接收的参数是需要绑定的属性名。如果不传递参数,,默认绑定到同名属性上。
注意:angular的HTML编译器对大小写敏感。
我们来看一下input的构造器到底干了什么?
@Input()
//给指令定义一个saTooltip属性,属性的值是表达式。
saTooltip:string;
(4)constructor构造器的理解
constructor(private el: ElementRef, private overlay: Overlay) {
//overloay是定义的overlay类
//我们来看一下ElementRef究竟是什么
console.log(el);
this.overlay.attach(el.nativeElement);
}
●私有属性el
首先,看一下el,也就是ElementRef是什么。根据打印结果,ElementRef就是app.html模板里包装好的div元素。
再来看attach。这行代码负责刚刚的原生div元素添加内容。
attach(target) {
target.appendChild(this.el);
//target是原生的div,给它添加子元素,内容是overloay定义的this.el
}
●私有属性overlay
overlay的类型为Overlay,也就是定义的class类。Overlay类实现了维护tooltip组件外观的逻辑,并可以用angular的DI依赖注入,当然要加上顶层组件Component的定义。
ch4/ts/tooltip/app.ts:
@Component({
selector: 'app',
templateUrl: './app.html',
providers: [Overlay],//数组哦,实现Overlay的依赖注入
directives: [Tooltip]
})
(5)封装指令要在顶层组件声明。
注意:声明的是数组哦。整个组件的内部全部指令都会声明在这里。尽管显式声明有些麻烦,但能带来更好的封装性。而在ng1种所有指令都在全局命名空间中,坏处是容易命名冲突。同时我们知道了组件用了哪些指令,更好理解了。
@Component({
//component装饰器,传递对象字面量作为参数
selector: 'app',
templateUrl: './app.html',
providers: [Overlay],
directives: [Tooltip]//声明指令数组,angular编译器就可以发现tooltip指令了
}) class App {}
五: 其他,重命名指令的输入输出、语法糖的本来面目
先回顾语法糖怎么书写的:
@Directive(...)
class Dir{
@Output()outputNmae=new EventEmitter();
@Input() inputName;
}
//最佳实践推荐的语法糖方式,更容易阅读和理解
本来面目是:
@Directive({
outputs:['outputName:XXXX'],
inputs:['inputs:XXXX']
})
class Dir{
outputName=new EventEmitter();
}
迈向angularjs2系列(2):angular2指令详解的更多相关文章
- Java系列:JVM指令详解(下)(zz)
九.自增减指令 20:iconst_1 21:istore_1 22:return 指令码 助记符 ...
- Java系列:JVM指令详解(上)(zz)
一.未归类系列A 此系列暂未归类. 指令码 助记符 说明 59:iastore 60:lload 6 //因为str ...
- ASP.NET MVC深入浅出系列(持续更新) ORM系列之Entity FrameWork详解(持续更新) 第十六节:语法总结(3)(C#6.0和C#7.0新语法) 第三节:深度剖析各类数据结构(Array、List、Queue、Stack)及线程安全问题和yeild关键字 各种通讯连接方式 设计模式篇 第十二节: 总结Quartz.Net几种部署模式(IIS、Exe、服务部署【借
ASP.NET MVC深入浅出系列(持续更新) 一. ASP.NET体系 从事.Net开发以来,最先接触的Web开发框架是Asp.Net WebForm,该框架高度封装,为了隐藏Http的无状态模 ...
- [转]JVM指令详解(上)
作者:禅楼望月(http://www.cnblogs.com/yaoyinglong) 本文主要记录一些JVM指令,便于记忆与查阅. 一.未归类系列A 此系列暂未归类. 指令码 助记符 ...
- C#中的预处理器指令详解
这篇文章主要介绍了C#中的预处理器指令详解,本文讲解了#define 和 #undef.#if.#elif.#else和#endif.#warning和#error.#region和#endregio ...
- rsync指令详解
rsync指令详解(更详细的看官方文档http://rsync.samba.org/ftp/rsync/rsync.html) [root@Centos epel]# rsync --help rsy ...
- #pragma 预处理指令详解
源地址:http://blog.csdn.net/jx_kingwei/article/details/367312 #pragma 预处理指令详解 在所有的预处理指令中, ...
- LDM与STM指令详解
title: LDM与STM指令详解 date: 2019/2/26 17:58:00 toc: true --- LDM与STM指令详解 指令形式如下,这里的存储方向是针对寄存器的 Load Mul ...
- C#中的预处理指令详解
这篇文章主要介绍了C#中的预处理指令详解,本文讲解了#define 和 #undef.#if.#elif.#else和#endif.#warning和#error.#region和#endregion ...
随机推荐
- 【NOI复习】树链剖分
简介 树链剖分通常用来解决一类维护静态树上路径信息的问题, 例如:给定一棵点带权树, 接下来每次操作会修改某条路径上所有点的权值(修改为同一个值或是同加上一个值等) , 以及询问某条路径上所有点的权值 ...
- RabbitMQ 知识总结
RabbitMQ知识总结 AMQP协议 AMQP协议是一个提供统一消息服务的应用层标准协议,并不会受到客户端/中间件不同产品.不同开发语言等条件的影响.RabbitMQ则是基于该协议实现的. 举个例子 ...
- 浅谈lvs和nginx的一些优点和缺点
借鉴一些网上资料整理了简单的比较: LVS的负载能力强,因为其工作方式逻辑非常简单,仅进行请求分发,而且工作在网络的第4层,没有流量,所以其效率不需要有过多的忧虑. LVS基本能支持所有应用,因为工作 ...
- python2.7 + selenium3.4.3浏览器的选择
大家都知道,selenium2对火狐浏览器兼容性比较好,和谷歌和IE相比,好处是无需安装相应的driver.exe来支持启动浏览器,但是缺点是最高支持火狐47版本. 现在selenium3出来了,是不 ...
- Node.js 入门:Express + Mongoose 基础使用
前言 Express 是基于 Node.js 平台的 web 应用开发框架,在学习了 Node.js 的基础知识后,可以使用 Express 框架来搭建一个 web 应用,实现对数据库的增删查改. 数 ...
- webpack2 前篇
webpack2 前篇 #webpack 前两天用了一天半时间琢磨了下webpack2,想起去年这时候,面对webpack1那样恶心的文档,前前后后搞了好几次才摸索清楚,那真是吐了. 划重点 其实we ...
- Windows环境下安装scikit-learn
scikit-learn是Python的一个机器学习库,请按照以下步骤进行安装. 1.首先确保你的机器安装了Python并且配置好了环境变量. 2.安装pip 下载地址:https://pypi.py ...
- grunt+bower依赖管理
安装bower(必须安装git) npm install bower -g bower按照插件命令 初始化配置 bower init 生成bower.json //如果有bower.json 直接输入 ...
- python中的类属性和实例属性
属性就是属于一个对象的数据或者函数,我们可以通过句点(.)来访问属性,同时 Python 还支持在运作中添加和修改属性. 我们先来看看类里面的普通字段: class Test(object): nam ...
- NYOJ--541--最强DE 战斗力(递推)
最强DE 战斗力 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 春秋战国时期,赵国地大物博,资源非常丰富,人民安居乐业.但许多国家对它虎视眈眈,准备联合起来对赵国发 ...