大屏中数据刷新要求像电表一样滚动更新效果。 由于大屏中使用较多,选择封装为一个可复用组件。主要思想: 将宿主组件传入的值,分解为独立的数字和小数点,每个数字Dom由宿主css样式决定宽度,并生成一个子级的滑块,通过数字的大小设置transition进行滚动。效果如下:
html部分:
为了满足数字滚动时先滚动一圈,然后在滚动到对应值的需求(避免0值无动画),numberSlider滑块中重复了一遍0~9。
<span class="data_updateable">
<span *ngFor="let item of valueList;" [ngSwitch]="item" class="dataWrapper">
<span *ngSwitchCase="'.'" class="dot">{{item}}</span>
<span *ngSwitchDefault class="numberItem">
<!-- 占位 宽度自适应 -->
<span style="visibility: hidden">{{item}}</span>
<span class="numberSlider" [@dataUpdate] ='item'>01234567890123456789</span>
</span>
</span>
</span>
ts部分:
将宿主传入的值生成数组, 由ngFor遍历生成对应Dom
import { Component, OnInit, OnChanges, Input} from '@angular/core';
import { AnimationDataUpdate } from '@/animations/animation-dataUpdate';
@Component({
selector: 'app-data-updateable',
templateUrl: './data-updateable.component.html',
styleUrls: ['./data-updateable.component.less'],
animations: [AnimationDataUpdate]
})
export class DataUpdateableComponent implements OnInit, OnChanges {
@Input() value: number;
public valueList: string[] = [];
constructor( ) { }
ngOnInit() {
}
ngOnChanges() {
if (this.value) {
this.valueList = this.value.toString().split('');
}
}
}
css部分:
numberSlider滑块中文本排列方式为writing-mode: vertical-rl; 竖直排列,便于滚动处理
.data_updateable {
display: flex;
height: 100%;
flex-direction: row;
justify-content: flex-end;
user-select: none;
.dataWrapper {
display: flex;
align-items: center;
height: 100%;
.dot {
display: inline-block;
height: 100%;
line-height: 100%;
vertical-align: top;
}
.numberItem {
position: relative;
display: inline-block;
height: 100%;
overflow: hidden;
.numberSlider {
position: absolute;
writing-mode: vertical-rl;
text-orientation: upright;
top: -2px;
left: 50%;
transform: translate(-50%, 0);
transition: transform 2s ease-in-out;
}
}
}
}
dataUpdate中的动画部分
设定每个值的滚动距离(每个值先滚动一圈,然后在滚动到对应的值)
import { trigger, state, transition, animate, style, } from '@angular/animations';
export const AnimationDataUpdate = trigger('dataUpdate', [
state('0', style({
transform: 'translate(-50%, -50%)'
})),
state('1', style({
transform: 'translate(-50%, -55%)'
})),
state('2', style({
transform: 'translate(-50%, -60%)'
})),
state('3', style({
transform: 'translate(-50%, -65%)'
})),
state('4', style({
transform: 'translate(-50%, -70%)'
})),
state('5', style({
transform: 'translate(-50%, -75%)'
})),
state('6', style({
transform: 'translate(-50%, -80%)'
})),
state('7', style({
transform: 'translate(-50%, -85%)'
})),
state('8', style({
transform: 'translate(-50%, -90%)'
})),
state('9', style({
transform: 'translate(-50%, -95%)'
})),
])
最后在宿主中调用方式
number为传入组件的值
<app-data-updateable [value]="number"></app-data-updateable>
因为前台需要30s更新一次数据,而数据库中10min中才发生变化,所以每次数据更新不是根据当前值进行滚动,而是从0重新开始,避免10分钟数据都没有变化。若需每次数字不从0重新渲染,则需要Dom不重绘。