进度条

作者 @barryrowe

本食谱演示了动态进度条的创建、模拟多个请求的管理,并在每个请求完成后更新总体进度。

进度条 - 图1

示例代码

(
StackBlitz
)

  1. import { Observable } from 'rxjs/Observable';
  2. import { of } from 'rxjs/observable/of';
  3. import { empty } from 'rxjs/observable/empty';
  4. import { fromEvent } from 'rxjs/observable/fromEvent';
  5. import { from } from 'rxjs/observable/from';
  6. import {
  7. delay,
  8. switchMapTo,
  9. concatAll,
  10. count,
  11. scan,
  12. withLatestFrom,
  13. share
  14. } from 'rxjs/operators';
  15. const requestOne = of('first').pipe(delay(500));
  16. const requestTwo = of('second').pipe(delay(800));
  17. const requestThree = of('third').pipe(delay(1100));
  18. const requestFour = of('fourth').pipe(delay(1400));
  19. const requestFive = of('fifth').pipe(delay(1700));
  20. const loadButton = document.getElementById('load');
  21. const progressBar = document.getElementById('progress');
  22. const content = document.getElementById('data');
  23. // 请求完成后更新进度条
  24. const updateProgress = progressRatio => {
  25. console.log('Progress Ratio: ', progressRatio);
  26. progressBar.style.width = 100 * progressRatio + '%';
  27. if (progressRatio === 1) {
  28. progressBar.className += ' finished';
  29. } else {
  30. progressBar.className = progressBar.className.replace(' finished', '');
  31. }
  32. };
  33. // 通知更新的简单辅助函数
  34. const updateContent = newContent => {
  35. content.innerHTML += newContent;
  36. };
  37. const displayData = data => {
  38. updateContent(`<div class="content-item">${data}</div>`);
  39. };
  40. // 模拟5个不同时长的请求
  41. const observables: Array<Observable<string>> = [
  42. requestOne,
  43. requestTwo,
  44. requestThree,
  45. requestFour,
  46. requestFive
  47. ];
  48. const array$ = from(observables);
  49. const requests$ = array$.pipe(concatAll());
  50. const clicks$ = fromEvent(loadButton, 'click');
  51. const progress$ = clicks$.pipe(switchMapTo(requests$), share());
  52. const count$ = array$.pipe(count());
  53. const ratio$ = progress$.pipe(
  54. scan(current => current + 1, 0),
  55. withLatestFrom(count$, (current, count) => current / count)
  56. );
  57. clicks$.pipe(switchMapTo(ratio$)).subscribe(updateProgress);
  58. progress$.subscribe(displayData);
html
  1. <div class="progress-container">
  2. <div class="progress" id="progress"></div>
  3. </div>
  4. <button id="load">
  5. Load Data
  6. </button>
  7. <div id="data">
  8. </div>

感谢 @johnlinquist 对本示例的帮助!

使用到的操作符