我想使用canvas元素在Angular 2中创建一个循环进度条。我已经在Angular 1中完成了多个项目,但我对Angular 2和TypeScript都是全新的,所以我有点沉闷......
我创建了一个ProgressCircle
组件,并使其可注入,因此我可以在其他组件中使用它。此进度组件从父组件接收一些属性,用于确定进度循环的外观以及填充方式。
注意:我从旧的ES5项目中删除了此代码。这可能会显示出来。
import { Component, Input, Injectable, ElementRef, AfterViewInit } from '@angular/core';
@Injectable()
@Component({
selector: 'progress-circle',
template: `
<div class="progress-indicator" [style.width]="size + 'px'" [style.height]="size + 'px'">
<canvas [attr.width]="size" [attr.height]="size"></canvas>
<span class="progress-text-container">
<span class="progress-text">{{ progress }}</span>
</span>
</div>
`
})
export class ProgressCircle implements AfterViewInit {
@Input() size:number;
@Input() progress:number;
@Input() lineWidth:number;
@Input() rotate:number;
@Input() color:string;
@Input() trackColor:string;
@Input() bgColor:string;
@Input() borderWidth:number;
@Input() animate:boolean;
constructor(private el:ElementRef) {}
ngAfterViewInit() {
this.draw();
}
draw() {
let canvas = this.el.nativeElement.getElementsByTagName('canvas')[0],
ctx = canvas.getContext('2d'),
options = {
percent: this.progress || 0,
size: this.size || 90,
lineWidth: this.lineWidth || (this.size / 10) || 10,
rotate: this.rotate || 0,
color: this.color || '#000',
trackColor: this.trackColor || '#e6e6e6',
bgColor: this.bgColor || 'transparent',
borderWidth: this.borderWidth || 0,
doAnimate: this.animate
},
radius = (options.size - options.lineWidth) / 2,
progress = 0,
fillColor:string = undefined,
animFrame:number, bg:ImageData;
let drawCircle = (strokeColor:string, fillColor:string, percent:number, hasBorder:boolean = false) => {
// logic to draw circle goes here
}
let animateProgess = () => {
if (++progress <= options.percent) { // we need to animate
// draw circle
animFrame = window.requestAnimationFrame(animateProgess);
}
}
ctx.translate(options.size / 2, options.size / 2);
ctx.rotate((-.5 + (options.rotate / 180)) * Math.PI);
if (options.doAnimate) {
bg = ctx.getImageData(0, 0, canvas.width, canvas.height);
animFrame = window.requestAnimationFrame(animateProgess);
} else {
drawCircle(options.color, fillColor, options.percent);
this.progress = Math.floor(options.percent);
}
}
}
现在,这很好用。但是,父组件的progress
输入变量可能随时发生变化。如何在适当的时间触发重绘我的进度条?
我无法初始化进度条,直到加载视图(因此调用ngAfterViewInit),否则它看起来很时髦,因为canvas元素尚未完全初始化。我查看了ngOnChanges生命周期钩子,但它没用,因为它在视图加载之前首先触发。
我有一个想法是让progress
输入变量可观察,然后在ngAfterViewInit
钩子中订阅它,但我不完全确定它是如何工作的。我还想我可以挂钩ngOnChanges
并检查它是否是第一个更改(实际上SimpleChange类根据文档有这样的方法),但它对我来说感觉有些讨厌。
非常感谢任何指针! Angular 2正在增长,但它肯定需要很多人习惯来自Angular 1 / ES5。
答案 0 :(得分:2)
使用ngOnChanges
。这是输入属性值更改时要通知的appropriate lifecycle hook to use。
至于在视图初始化之后等待...我会ngAfterViewInit
设置一个ngOnChanges
每次运行时检查的标志:
export class ProgressCircle implements AfterViewInit {
viewInitialized = false;
...
ngOnChanges() {
if(!viewInitialized) return;
...
}
ngAfterViewInit() {
viewInitialized = true;
...
}
ngOnChanges
可能有某种方式来确定视图是否已初始化,但我不知道(如果您知道某种方式发布评论,并且它比标志更有效)