Angular开发总会遇到诸多的问题,这里我将自己在开发中遇到的主要问题总结一番,方便自己偶尔翻查,也兴许能够帮大家解决些问题。
说明:*本文持续更新*,所贴代码由于篇幅限制,有些只是部分,建议直接去GitHub-ISSUE中去看
目录
- [innerHTML]中的JavaScript不能执行吗?
- 同时订阅路由参数和查询参数即params和queryParams
- 多异步请求并行处理
- *ngFor遍历对象属性
- 组件类的继承性
- 如何使组件样式超出组件作用域
- 下拉列表选项布尔类型转换
- 模板标签
、 - CLI下index.html页面未模板化,如何动态更改内容
- CLI下如何添加第三方CSS
- httpclient下的拦截器使用
[innerHTML]中的JavaScript不能执行吗?
答案:YES,不行的,这个牵扯到Angular的安全机制,官方介绍看这里
Angular官方的意思是倘若支持了这个,便存在攻击性,本身就是很可怕的,试想,Angular本身就是个JS框架,倘若支持了html代码块可执行JS,本身就会打破这个框架,带来致命的安全问题。
另外对于HTML,想让NG支持解析,需要注入DomSanitizer服务,将HTML标记位可信任。如果web中常用,建议做成管道,例子看这里
另外使用bypassSecurityTrustHtml,经测试,情况如下
- 页内CSS正常
- 外链CSS正常
- 执行JS不可以
- 嵌入媒体正常
如果我们还是希望能够执行HTML代码块中的JS,其实就需要换个角度去解决,比如iframe?对吧,总是有办法的。
同时订阅路由参数和查询参数即params和queryParams
进入一个视图页面时候,我们经常需要订阅参数,参数是有很多类型的,路径参数、查询参数,锚点参。我们如果利用嵌套形式写的话,会是这样子:
this.route.queryParams.subscribe(qparams => {
alert(qparams['title']);
this.route.params.subscribe(params => {
alert(params['id']);
});
})
但是这样子的代码是极难维护的,其实RXJS有对应的解决办法,可以这样子实现
let obsCombined = Observable.combineLatest(this.route.params, this.route.queryParams, (params, qparams) => ({
params,
qparams
}));
obsCombined.subscribe(ap => {
console.log(ap);
let params = ap['params'];
let qparams = ap['qparams'];
alert(qparams['title']);
alert(params['id']);
});
这样子减少了嵌套,代码直接清爽不少。
注意一个细节:import {Observable} from "rxjs/Rx";
写成import {Observable} from "rxjs/Observable";会报错误Property 'combineLatest' does not exist on type 'typeof Observable'.
*ngFor遍历对象属性
有时需要遍历对象属性,但是Angular的ngFor指令是只支持遍历数组的,所以需要转换对象,这个时候可以考虑封装个管道,代码如下
import {Pipe, PipeTransform} from "@angular/core";
/**
* 对象返回数组
*/
@Pipe({
name: 'keys'
})
export class KeysPipe implements PipeTransform {
transform(value: any, args?: any): any {
return Object.keys(value);
}
}
实际上,就是用了JS的Object.keys()方法,该方法作用如下
The Object.keys() method returns an array of a given object’s own enumerable properties, in the same order as that provided by a for…in loop (the difference being that a for-in loop enumerates properties in the prototype chain as well).
管道做好后,使用方法如下:
<div *ngFor="let key of facetFields|keys">
key:{{key}},
value:{{facetFields[key]}}
</div>
多异步请求并行处理
有时需要多请求结果同时进行处理,嵌套去做的话,会是如此
this.http.get('/api/test1')
.subscribe(res1 => {
this.http.get('/api/test2').subscribe(res2 => {
this.res1 = res1;
this.res2 = res2;
});
});
这种结构臃肿,难以维护,使用Rxjs的forkJoin操作符
const req1 = this.http.get('/api/test1');
const req2 =this.http.get('/api/test2');
Rx.Observable.forkJoin(req1, req2).subscribe(
res => {
this.res1 = res[0];
this.res2 = res[1];
))
只有当多请求结果都得到时,才会通知我们
组件类的继承性
ng-v2.3版本加入了对于组件继承性的支持,这样进一步的提升代码的复用性。
组件继承性说明:
- meta注解,比如@input,@output
- 构造函数
- 组件生命周期
以上三者均支持复用,官方说明看这里,链接
如何使组件样式超出组件作用域
如何使得A组件的样式在A的子组件比如B中能够使用的
除了将样式写外链CSS即全局CSS之外,其实还可以修改视图封装模式即view encapsulation mode达到组件样式可以出去,使得其他组件可以使用。只需要配置比如A组件的视图模式,如下配置
@Component({
selector: 'app-css',
templateUrl: './css.component.html',
styleUrls: ['./css.component.css'],
encapsulation: ViewEncapsulation.None
})
如上,则该组件下的各级组件dom元素均可使用该样式。
注意
组件继承不支持模板和样式,任何操作dom的行为都应该物理分离。
下拉列表选项布尔类型转换
当我们对下拉列表进行ngModel双向绑定,如果我们的对象是非字符串类型,比如boolean,当用户选择选项后,会变成字符串。
如果下拉选项被提供了非字符串类型,缺省value是会进行字符串类型转换,如果使用ngValue,就可以保持类型不变。
<select [(ngModel)]="isList" (ngModelChange)="viewTypeChanged()">
<option [ngValue]="true">列表浏览</option>
<option [ngValue]="false">分组浏览</option>
</select>
模板标签、
ng-template我们经常搭配ngIf指令等使用,如下:
<div *ngIf="isList;else elseBlock">
<ul>
<li *ngFor="let item of items">
<a routerLink='../detail/{{item.id}}' [queryParams]="{title:item.title}">

