问题
如何配置一个在大屏幕和小屏幕上都很好用的 Material cdk 覆盖位置策略?
目标
我的目标是创建一个覆盖 Angular overlay CDK , 遵循以下规则:
什么有效 😎
我已经完成了上述一些要求,正如您在此处看到的,定位在具有足够垂直空间(在本例中为 512 像素)的设备上效果很好:
破损的部分😅
但是,从下面的 gif 图中可以看出,这个 不工作在垂直空间不足的小型设备上(在本例中为 255 像素)。实际上,正如您从 GIF 中看到的那样,在其中 2 种情况下,它非常接近。位置是正确的,只是高度偏离了。
这里的目标是使用可用空间,如红色所示:
代码🤓
我有一个堆栈 Blitz ,你可以在其中进行实验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;
}
笔记
我一直在考虑在视口(viewport)高度变小的时候使用全局定位策略。但是,我宁愿避免这种情况,因为我希望有一个解决方案可以处理覆盖层的任何高度(尊重最大偏离航向)。
在测试 stackblitz 时,我建议使用 stackbllitz 的“在新窗口中实时打开”功能。链接是here again .
如果您能帮助解决此问题或为我指明正确的方向,我将不胜感激🤷🏾♂️
最佳答案
我通过在打开对话框后执行检查解决了上述问题。这是通过调整大小观察器完成的。代码如下所示:
/*
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 :
关于angular - 如何配置一个在大屏幕和小屏幕上都很好用的 Material cdk 覆盖位置策略?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58674359/