جاوااسکریپت - چگونه تشخیص تغییر را مدیریت کنم وقتی از runOutsideAngular fromEvent استفاده میکنم؟


در برنامه انگولار خود به رویداد resize گوش میکنم و نام نقطه شکست را در موضوع breakpointChanged بهروزرسانی میکنم:

 breakpointChanged = new Subject();

  resize$ = fromEvent(window, "resize").pipe(
    startWith(() => []),
    map(() => [window.innerHeight, window.innerWidth]),
    tap(([height, width]) => {
      const name = this.breakpoint(width);

      this.breakpointChanged.next(name);
    })
  );

بر اساس نام نقطه شکست تصمیم گرفتم که کشو باز باشد یا نه:

drawerOpened$ = this.breakpointChanged.pipe(
    distinctUntilChanged(),
    map((breakpointName) => {
      return breakpointName !== "xs"; // if it's not xs breakpoint then it's true mean it's open.
    })
  );

من همچنین میخواهم از distinctUntilChanged استفاده کنم زیرا اگر نقطه شکست تغییر نکرده باشد، نمیخواهم جریان فعال شود.

و در ngOnInit من به جریان resize مشترک میشوم. و این کار را در runOutsideAngular انجام میدهم، بنابراین هر بار که تغییر اندازه رخ میدهد، تشخیص تغییر را فعال نمیکنم.

 this.zone.runOutsideAngular(() => {
   this.resize$.subscribe();
 });

مشکل این است که نما بهروزرسانی نمیشود.

فقط وقتی که من this.breakpointChanged.next(name); را با this.zone.run(() => {}) میبندم، کار میکند، اما اگر این کار را انجام دهم، تشخیص تغییر فعال میشود - همیشه وقتی تغییر اندازه اتفاق میافتد. که این موضوع بد است.

ایدهای داری که چطور این مشکل را حل کنیم و آن را مرتب و تمیز کنیم؟

در همان زمینه، چگونه لوله async تشخیص تغییر انجام نمیدهد؟ مقدار در حال تغییر است و async باید مشترک شود و زمانی که مقدار تغییر میکند، فعال شود.

codesandbox.io

پاسخ شماره ۱

این سوال خوبی است. ممکن است بتوانیم پیچیدگی را با استفاده از debounceTime() به صورت زیر کاهش دهیم:

  resize$ = fromEvent(window, "resize").pipe(
    startWith(() => []),
    debounceTime(1000),
    map(() => [window.innerHeight, window.innerWidth]),
    tap(([height, width]) => {
      console.log(height);
      const name = this.breakpoint(width);
      this.breakpointChanged.next(name);
    })
  );

و حذف this.zone.runOutsideAngular

  ngOnInit() {
      this.resize$.subscribe();
  }

مهم نیست چند بار تغییر اندازه داده شود، این رویداد پس از ۱ ثانیه ارسال خواهد شد.

در اینجا چیزی است که در مثال شما امتحان کردم.

به من بگو اگر این کمک میکند

پاسخ شماره ۲

  • یک debounceTime(250) به عنوان اولین پارامتر fromEvent(...).pipe(...) اضافه کنید

  • همانطور که قبلاً انجام میدادید، breakpoint.next را در zone.run(..) قرار دهید و همچنین همان روش runOutsideAngular را حفظ کنید

تشخیص تغییر بعد از هر دوره ۲۵۰ میلیثانیه اجرا خواهد شد، همان چیزی که شما به دنبالش هستید - تجربه کاربری خوب بهعلاوه تشخیص تغییر محدود/کم