Angular速成2 基本开发#
这次主要找一套模板,看一下各个问题点。
推荐先大致看一下这两本书,跑一下代码。是最新的angular12版本。 <<Angular Projects - Second Edition Build modern web apps by exploring Angular 12 with 10 different projects and cutting-edge technologies>> https://github.com/PacktPublishing/Angular-Projects-Second-Edition <<Angular Cookbook Over 80 actionable recipes every Angular developer should know>> https://github.com/PacktPublishing/Angular-Cookbook
结合官方文档和之前的几本书: << ng-book The Complete book on Angular>> << Getting Started With Angular>> << Learning Angular>>
另外需要各种js/ts的书和教程做参考。
模板#
themeforest.net 是一个模板网站。搜angular 12可以找到不少模板。 我买的这个 https://themeforest.net/item/minible-angular-admin-dashboard-template/31165271 ui库用的是Bootstrap。 这些模板一般二三十美元一个,会持续更新,包括更新angular版本。 一般包含几种排版,明暗主题,二十个左右常用例子页面,如登录注册、产品列表、dashboard页面等。 和所有的组件示例。 适应手机平板等。 代码也是比较清晰的。足够初学者学一阵子的。值得购买。
我还买了fuse模板。发现结构和代码挺相似。不知道谁抄谁的。
Minible模板#
把minible模板的代码跑起来 进代码Admin目录 可能需要安装
ng add @angular-devkit/build-angular
ng serve --host 0.0.0.0
可用ip访问4200端口依赖 看package.json,跟一个ng new新建的项目比较。看看它用来哪些主要的库。 先不要改动,等以后熟练了再说。 ng-bootstrap chart ckeditor 等等各种
总体结构 app.module.ts里bootstrap默认是AppComponent
app-routing.module.ts里定义路由。默认初始组件是LayoutComponent。
Route的配置 https://angular.io/api/router/Route
用loadChildren可以设置lazy load。打开组件才加载相关文件。
canActivate可以配置一些逻辑,来决定当前用户能否打开这个组件。
LayoutComponent里存一个当前排版的标志,控制页面的总排版,比如横还是竖。 然后横竖各做一个组件。根据当前标志显示对应的排版即可。
以横板为例,horizontal.component.html包含顶部的
。 中间 是按当前路由显示各种功能页。 底部的 。 右边有 ,点击齿轮按钮会滑出。 账号相关功能 login.component.ts包含登录框架,调用authFackservice的login来登录。 这个模板把service统一放一起。 AuthfakeauthenticationService.login用http请求后端登录接口。 成功后可以用localStorage存数据。 成功后跳转 this.router.navigate([‘/dashboard’]); 注册等页面同理。
路由设置里有个canActivate,配置为AuthGuard。 auth.guard.ts里实现canActivate逻辑。 检查AuthfakeauthenticationService里设置的数据。 如果设置了正确的状态,判断为已登录,返回true。否则跳转到/account/login,返回false。
看代码 再结合各种文档和书籍,研究各个例子页面的代码和组件用法即可。
其他js/ts知识#
这里可以在线测试ts代码 https://www.typescriptlang.org/play
js/ts的异步机制#
promise#
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
如果要进行好几个操作,如果是异步一般用callback,可能出现大量的callback。 如果是同步,需要逐个处理每个操作的结果。 都可能导致混乱或难看。 比如要读好几个文件,或者发多次http。
用promise搭配then等语法可以把这种程序做得比较简洁。 例如
fs.promises.readFile("./test1.txt")
.then((value) => {
console.log(`ps test1.txt read : ${value}`);
return fs.promises.readFile("./test2.txt");
}).then((value) => {
console.log(`ps test2.txt read : ${value}`);
return fs.promises.readFile("./test3.txt");
}).then((value) => {
console.log(`ps test3.txt read : ${value}`);
}).catch((error) => {
console.log(`an error occurred : ${error}`);
});
调用fs库接口的promise版本,会返回一个promise对象。 可以对promise对象用then/catch。如果promise是成功的,走then,否则就是出错走catch。 这样可以一行顺着写完。非常清晰。
一个Promise本质上是一个异步操作,一定会走一个异步的过程,无法同步完成一个Promise。 本质上也是一种callback。
主动起promise需要提供一个函数pf。pf有两个参数resolve和reject,都是返回void的函数。 成功时调resolve,失败时调reject。
function delayedPromise(): Promise<void> {
// return new Promise object
return new Promise<void>( // start constructor
(
resolve: () => void, // resolve function
reject: () => void // reject function
) => {
// start of function definition
function afterTimeout() {
resolve();
}
setTimeout(afterTimeout, 1000);
// end of function definition
}
); // end constructor
}
可以设置promise的数据类型,比如Promise<Product[]>。 resolve的参数类型得和promise保持一致,而reject不必。
function delayedPromise(timeout: number): Promise<number> {
// return new Promise object
return new Promise<number>( // start constructor
(
resolve: (timeout:number) => void, // resolve function
reject: () => void // reject function
) => {
// start of function definition
function afterTimeout() {
resolve(timeout);
}
setTimeout(afterTimeout, timeout);
// end of function definition
}
); // end constructor
}
这里改成了可设置定时,并返回传入的时长。
delayedPromise(3000).then((value) => {console.log(value)})
delayedPromise(1000).then((value) => {console.log(value)})
注意到1秒后先打印了1000,3秒后打印了3000。 起一个Promise是起了一个异步操作,不会阻塞,而是直接往下走,等结果来了再走回调。
async/await#
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
js本身是单线程的,事件驱动的。回调也只不过是注册事件,本质还是单线程。
之前起了2个Promise,直接开始执行,不会阻塞。 有时我们需要等某个Promise有了结果才往下走,就得用async/await。
用async声明函数后,函数一定返回一个Promise。如果没有显示返回Promise,会做隐式转换。
await用来等待一个Promise,直到Promise有了结果才往下走。 await必须写在async函数里。
async function wtf() {
await delayedPromise(3000).then((value) => {console.log(value)});
delayedPromise(1000).then((value) => {console.log(value)});
}
wtf();
// 这样搞,3秒后打印3000,再过1秒打印1000。
可以直接取Promise的结果
async function wtf() {
let a = await delayedPromise(3000);
console.log(a);
delayedPromise(1000);
}
wtf();
这时如果Promise被reject,在await处会挂掉。 我的环境下现象貌似是整个环境挂掉,wtf剩下的代码不再执行。已经起的Promise还是会正常跑。 加上try/catch可以抓到reject。
async function wtf() {
try {
let a = await delayedPromise(3000);
console.log(a);
} catch(error){
console.log(`${error}`);
}
delayedPromise(1000);
}
wtf();
js有很多不同的运行环境,如果不处理reject,可能出各种问题。 一般推荐所有await都用上try/catch。
Promise VS Observable#
那么Promise和Observable感觉本质都是个回调。有啥区别?应该用哪个? https://stackoverflow.com/questions/37364973/what-is-the-difference-between-promises-and-observables
貌似主推Observable。 目前感觉Observable会更容易操作,只是请求一两个http的场景貌似更合适。
Observable可以转化成Promise https://rxjs-dev.firebaseapp.com/api/index/function/lastValueFrom
rxjs#
Observable “可观察”的数据。rxjs的基石。
Subject 一种Observable。可以让监听的数据广播。 ReplaySubject 一种Subject。会replay一次老的值给新的订阅者。
angular的一些常用概念#
component里做逻辑,处理数据,与模板(html)交互和数据绑定。
一般来说一个service不应横跨多个模块。 service的一些常见功能: 用http请求服务端数据 与浏览器的本地数据交互 log处理 数据传输
几种数据绑定
<li>{{hero.name}}</li>
数据从component到template。直接拿component的hero变量。
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
https://angular.io/guide/property-binding
数据从component到template。
拿出component的selectedHero变量赋给hero。
即把app-hero-detail对应组件的hero赋了值。常用来传数据到子组件。
<li (click)="selectHero(hero)"></li>
https://angular.io/guide/user-input#binding-to-user-input-events
事件绑定到组件的函数。
<input type="text" id="hero-name" [(ngModel)]="hero.name">
https://angular.io/api/forms/NgModel
input内容和组件数据的双向绑定。
angular library#
可以用angular做库,把功能做到库里,进行分享和复用。 暂时不会。以后再学。
到此可以做一个简单的前端项目了。比如做一个博客(需要找一些angular的markdown库)。