【问题标题】:How do I configure a material cdk overlay position strategy that works great, both on big and small screens?如何配置一个在大屏幕和小屏幕上都很好用的材质 cdk 覆盖位置策略?
【发布时间】:2020-02-28 15:27:19
【问题描述】:

问题

如何配置一个在大屏幕和小屏幕上都很好用的材质 cdk 叠加位置策略?

目标

我的目标是使用Angular overlay CDK 创建一个覆盖,遵循以下规则:

  • 切勿将叠加层放置在视口之外
  • 最大高度为 300 像素
  • 位置覆盖 y,优先级为顶部,中间底部。
  • 在高度低于 300 的屏幕上,使用可用高度。
  • 换句话说,没有最小高度。

什么有效 ????

我已经完成了上面的一些要求,正如你在这里看到的那样,定位在具有足够垂直空间(在本例中为 512px)的设备上效果很好:

破损的部分????

但是,从下面的 gif 图中可以看出,这在垂直空间不足(在本例中为 255 像素)的小型设备上不起作用。实际上,正如您从 GIF 中看到的那样,在其中 2 种情况下,它非常接近。位置是正确的,只是高度偏了。

这里的目标是使用可用空间,如红色所示:

代码??????

我有一个堆栈闪电战,你可以在那里试验here

组件

openPopup(element: any) {
    const overlayRef = this.overlay.create({
      hasBackdrop: true,
      positionStrategy: this.overlay.position()
      .flexibleConnectedTo(element)
      .withLockedPosition()
      .withPositions([
        {
          panelClass: 'custom-panel1',
          originX: 'center',
          originY: 'center',
          overlayX: 'start',
          overlayY: 'top',
        },
        {
          panelClass: 'custom-panel2',
          originX: 'center',
          originY: 'center',
          overlayX: 'start',
          overlayY: 'center',
        },
        {
          panelClass: 'custom-panel3',
          originX: 'center',
          originY: 'center',
          overlayX: 'start',
          overlayY: 'bottom',
        },
      ])
      ,
      width: '200px',
      maxHeight: 300,
    });

    const popupComponentPortal = new ComponentPortal(PopupComponent);

    overlayRef.attach(popupComponentPortal);

    overlayRef.backdropClick().subscribe(() => {
      overlayRef.dispose();
    });
  }

全局样式

.cdk-overlay-pane {
    max-height: 300px;
}

注意事项

我一直在考虑在视口高度变小的时候使用全局定位策略。但是,我宁愿避免这种情况,因为我希望有一个解决方案可以处理覆盖层的任何高度(考虑偏离航向的最大高度)。

我建议在测试 stackblitz 时使用 stackbllitz 的“在新窗口中实时打开”功能。链接是here again

如果您能帮助解决这个问题或为我指明正确的方向,我将不胜感激????????‍♂️

【问题讨论】:

    标签: angular angular-material angular-material2 angular-cdk


    【解决方案1】:

    我通过在对话框打开后执行检查解决了上述问题。这是通过调整大小观察器完成的。代码如下所示:

    /*
            Read more about the resize observer here: https://developers.google.com/web/updates/2016/10/resizeobserver
            Basicaly, what we do is that we subscribe to size events on the overlay.
            Currently we only get one event, (then we disconnet the resize observer).
            But then we simply calculate if we need to improve the layout.
            */
            const ro = new ResizeObserver(entries => {
                for (const entry of entries) {
                    // We get the hight of the element from the the contnetRect, provided by the resize observer
                    const height = entry.contentRect.height;
    
                    const { left: x, top: y } = entry.target.getBoundingClientRect();
    
                    const offsetPlusHeight = y + height;
    
                    const pixelsOverflow = offsetPlusHeight - this.viewPortHeight;
                    // If y is negative, we are off-screen to the top.
                    // If pixelsOverflow is positive, we are off-screen on the bottom
                    // In either case, we adopt a new strategy.
                    if (y < 0 || pixelsOverflow > 1) {
                        ro.disconnect();
                        overlayRef.updateSize({
                            height: height,
                            maxHeight: config.maxHeight,
                            width: config.width,
                        });
                        // Trust the initial positioning strategy, in terms of the x coordinate
    
                        // Now determine if we need to throw the overlap, all the way to the top.
                        const delta = this.viewPortHeight - height;
                        const yOffset = delta > 0 ? delta : 0;
    
                        // Finnaly, we can apply canculate and apply the new position
                        const newPositionStrategy = this.getGlobalPosition(yOffset, x);
                        overlayRef.updatePositionStrategy(newPositionStrategy);
                    }
                }
            });
    
            // Element for which to observe height and width
            ro.observe(overlayRef.overlayElement);
    

    我认为我需要这个额外检查的原因是因为我真正在寻找的是一个用于可变高度项目的 n cdk 覆盖策略。

    如果您对有效的解决方案感兴趣,我有一个有效的stackblitz here

    【讨论】:

      【解决方案2】:

      对于高度,您可以替换:

      maxHeight: 300,
      

      通过

      height: window.innerHeight < 300 ? window.innerHeight + 'px' : '300px',
      

      这只是一个想法。在你的组件中直接使用 window 不是一个好主意,因为你不能模拟它。如果您想知道如何正确操作,请查看this article

      【讨论】:

      • 嗨@Wandrille - 感谢您的回答。像建议的那样设置高度,并不能解决小屏幕上的定位问题。叠加层继续位于视口之外。
      • 我没有找到很好的解决方案,抱歉。
      猜你喜欢
      • 2020-08-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多