react-Leaflet中Popup尺寸不随内容变化大小问题

通过 react-leaflet 在 react 中使用 leaflet,在动态修改 Popup 弹窗内容时,发现 Popup 尺寸(宽高)不会跟随修改后的内容变化。

问题

有一个默认小尺寸的 Popup,它里面有一个按钮。点击按钮后会将 Popup 中的内容替换成大尺寸内容。

简要逻辑如下:

<Popup>
{this.state.fullBtnClicked ? bigContent : smallContent}
</Popup>

替换内容后,发现 Popup 的尺寸并未变大。

尝试添加minWidth/maxWidth属性:

<Popup
    maxWidth={this.state.fullBtnClicked?  bigMaxSize: smallMaxSize}
    minWidth={this.state.fullBtnClicked? bigMinSize : smallMinSize}
>
    {this.state.fullBtnClicked ? bigContent : smallContent}
</Popup>

替换内容后,Popup 的尺寸仍未变大,且 leaflet 仍然沿用初始化时的minWidth/maxWidth

原因

leaflet 会根据计算值为 Popup Content 添加一个width = xxx样式(Height 同理但稍有不同)。

计算方法在 leaflet/Popup.js 的 _updateLayout中:

style.width = '';
style.whiteSpace = 'nowrap';

var width = container.offsetWidth;
width = Math.min(width, this.options.maxWidth);
width = Math.max(width, this.options.minWidth);

style.width = (width + 1) + 'px';
style.whiteSpace = '';

style.height = '';

var height = container.offsetHeight,
maxHeight = this.options.maxHeight,
scrolledClass = 'leaflet-popup-scrolled';

if (maxHeight && height > maxHeight) {
    style.height = maxHeight + 'px';
    DomUtil.addClass(container, scrolledClass);
} else {
    DomUtil.removeClass(container, scrolledClass);
}

其中最关键的便是 this.options 了。

一路追查,发现 options 的路径为:

  • [@react-leaflet]SomeWork
    • [react-leaflet]createDivOverlayComponent.createOverlayComponent
      • [leaflet]new Popup(props,ref)
        • [leaflet]popup.initialize(props,ref)
          • [leaflet]options = props

问题明确:

  • leaflet 这个包是传统 js,不是 React 组件。
  • react-leaflet 给 leaflet 套了个 React 空壳,壳里的内容实际为 leaflet 和它的 Dom。
  • props 发生变化时,react-leaflet 仅针对 position 做了监听更新,未处理 className、minWidth 等属性的更新。

当然,我不是专业的 Web 前端。

解决方法

方法0:使用我修改好的 react-leaflet

package.json中的依赖修改成我传的包:

"dependencies":{
    "react-leaflet": "npm:@azimiao/react-leaflet"
}

方法1:改 react-leaflet

修改 Popup.tsx,使其监听minWidth/maxWidth变化来更新 leaflet 中的 options 值,并重新计算 layout:

function usePopupLifecycle(
        element: LeafletElement<LeafletPopup>,
        context: LeafletContextInterface,
        // 梓喵出没(azimiao.com)修改 1,添加了 width/height
        { position, minWidth, maxWidth, maxHeight },
        setOpen: SetOpenFunc,
    ) {
        // 前面代码略……
        // 梓喵出没(azimiao.com)修改 2,监听变化
        const firstUpdate = useRef(true)
        useLayoutEffect(() => {
          if (firstUpdate.current) {
            firstUpdate.current = false
            return
          }
          const { instance } = element
          if (minWidth != null) {
            instance.options.minWidth = minWidth
          }
          if (maxWidth != null) {
            instance.options.maxWidth = maxWidth
          }
          if (maxHeight != null) {
            instance.options.maxHeight = maxHeight
          }
          instance.update()
        }, [element, minWidth, maxWidth, maxHeight])
    }

方法2:Bug 就是 feature

通过 props 给minWidth传个 string 类型的值(如auto), Popup 计算 layout 时会出现错误结果(NaN),其赋值的 style 将没有意义。

通过 CSS 限制 content 内容尺寸,控制窗口大小。

方法3:改 leaflet

修改 _updateLayout方法,在minWidth/maxWidth为 string 或为 null 情况下,不设置 style,默认被 child 撑开即可。

同样通过 CSS 限制 content 内容尺寸来控制窗口大小。

我虽然不是专业前端,但我建议使用方法 1。

梓喵出没博客(azimiao.com)版权所有,转载请注明链接:https://www.azimiao.com/9640.html
欢迎加入梓喵出没博客交流群:313732000

发表评论

*

*