Angular 调整服务大小

Angular resize service

我正在尝试创建一个 Observable,如果 window 屏幕小于或小于 520 像素,它将发出 true 或 false 值。 所以我有下面的代码:

@Injectable({
  providedIn: 'root'
})
export class ResizeService {
  private mobileView$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
  mobileViewObs$ = this.mobileView$.asObservable();
  isMobile = false;
  size!: {width: number, height: number};
  constructor() {
   }

  resizeEvent(){
     fromEvent(window, 'resize').pipe(throttleTime(500), debounceTime(500)).subscribe((resizeEvent: any) => {
      this.size = {
          width: +resizeEvent.currentTarget.innerWidth,
          height: +resizeEvent.currentTarget.innerHeight
      }; 
      
      this.isMobile = this.isMobileView(this.size);

      this.mobileView$.next(this.isMobile);
    });;
  }

  isMobileView(size: {width: number, height: number}){
    if(size.width < PHONE_SIZE.width && size.height < PHONE_SIZE.height){
      return true;
    } else {
      return false;
    }
  }
}

它工作正常,但问题是我无法设置页面的初始大小。我不知道如何将尺寸对象从组件发送到服务。这是我的 component.ts:

@Component({
  selector: 'app-books-list',
  templateUrl: './books-list.component.html',
  styleUrls: ['./books-list.component.scss'],
})
export class BooksListComponent implements OnInit {
  @Input() book!: BookModel;

  booksArray: BookModel[] = [];
  oneBook!: BookModel;
  isMobile: boolean = false;
  size!: {width: number, height: number};

  constructor(private service: BookService, private route: ActivatedRoute,
    private resizeService: ResizeService) {}
  
  ngOnInit(): void {
    this.size = {width: window.innerWidth, height: window.innerHeight};
    
    this.resizeService.resizeEvent();
    this.resizeService.mobileViewObs$.subscribe(data => {
      this.isMobile = data;
    })

    this.service.getBooks().subscribe((books) => {
      this.booksArray = books;
    });
  }

问题是第一次重新加载页面时它总是显示为 false,因为 observable 仅在调整大小事件时创建。你知道如何实现这个功能吗?

您应该使用 ngAfterViewInit 而不是 ngOnInit。您需要在组件开始渲染时获取尺寸。但是,ngOnInit 用于初始化所有数据绑定属性。

@Component({
  selector: 'app-books-list',
  templateUrl: './books-list.component.html',
  styleUrls: ['./books-list.component.scss'],
})
export class BooksListComponent implements OnInit, AfterViewInit {
  @Input() book!: BookModel;

  booksArray: BookModel[] = [];
  oneBook!: BookModel;
  isMobile: boolean = false;
  size!: {width: number, height: number};

  constructor(private service: BookService, private route: ActivatedRoute,
    private resizeService: ResizeService) {}
  
  ngOnInit(): void {
    this.size = {width: window.innerWidth, height: window.innerHeight};
    

    this.service.getBooks().subscribe((books) => {
      this.booksArray = books;
    });

   ngAfterViewInit() {
   // removed this from ViewInit
   this.resizeService.resizeEvent();
    this.resizeService.mobileViewObs$.subscribe(data => {
      this.isMobile = data;
    })
    }
  }


查看 here 了解有关如何使用生命周期挂钩的更多详细信息。

实际上您不需要那么多代码,您可以直接在服务中将 truefalse 分配给您在组件中订阅的可观察对象。假设您想根据 mobile/desktop 视图在模板中显示不同的内容,那么使用 async 管道是一个完美的场景!

如果你需要组件ts中的true/false,你当然可以订阅,但记得取消订阅你正在走的路!

无论如何,我建议如下...

服务:

isMobile$ = fromEvent(window, 'resize').pipe(
  startWith(window), // to have an initial value, can be any value
  mapTo(window), // map to window object instead (so we can have the initial value!)
  throttleTime(500),
  debounceTime(500),
  map((window: Window) => {
    if (window.innerWidth < PHONE_SIZE.width && window.innerHeight < PHONE_SIZE.height) {
      return true;
    }
    return false;
  })
);

在组件中你只需要做....

isMobile$ = this.resizeService.isMobile$;

然后使用 async 管道或订阅!

HERE'S A DEMO - 这里只考虑屏幕宽度以便于测试:)