使用react-sizeme解决react-grid-layout中侧栏(抽屉)展开或隐藏时不会自适应容器大小的问题

news2024/11/25 4:33:35

文章目录

    • 使用react-sizeme解决react-grid-layout中侧栏(抽屉)展开或隐藏时不会自适应容器大小的问题
      • 前提概要
      • 问题代码
      • 解决代码
      • 参考

使用react-sizeme解决react-grid-layout中侧栏(抽屉)展开或隐藏时不会自适应容器大小的问题

前提概要

在上一篇博文中,我们讲到了使用react-grid-layoutecharts-for-react实现一个自定义的dashboar页面
《使用react-grid-layout和echarts-for-react实现一个支持拖拽的自定义响应式dashboard页面》

问题代码

import React, {useState} from "react";
import 'react-grid-layout/css/styles.css'
import 'react-resizable/css/styles.css'
import {Button} from "antd";
import {findIndex, uniqueId} from "lodash";
import './dashboard.css'
import WidgetLoadingSpin from "@/pages/Dashboard/Detail/WidgetLoadingSpin";
import {CloseOutlined, LockOutlined, QuestionCircleOutlined, UnlockOutlined} from "@ant-design/icons";
import RGL, {Layout, WidthProvider} from "react-grid-layout";
import {cloneDeep} from "lodash-es";
const BarChartWidgetLazy = React.lazy(() => import('@/pages/Dashboard/Detail/Widget/BarChartWidget'));
const PieChartWidgetLazy = React.lazy(() => import('@/pages/Dashboard/Detail/Widget/PieChartWidget'));
const ReactGridLayout = WidthProvider(RGL);
interface DashboardWidgetInfo {
  widgetName: string,
  layout: Layout
}
function DashboardGird() {
  const [widgets, setWidgets] = useState<DashboardWidgetInfo[]>([]);
  const getLayouts: any = () => {
    return cloneDeep(widgets.map(item => item.layout));
  }
  const setLayoutStatic = (widget: DashboardWidgetInfo, staticFlag: boolean) => {
    const index = findIndex(widgets, (w: any) => w.widgetName === widget.widgetName);
    if (index !== -1) {
      const updateWidget = widgets[index];
      updateWidget.layout.static = staticFlag;
      widgets.splice(index, 1, {...updateWidget});
      const newWidgets = [...widgets];
      setWidgets(newWidgets);
    }
  }
  const lockWidget = (widget: DashboardWidgetInfo) => {
    setLayoutStatic(widget, true);
  }
  const unlockWidget = (widget: DashboardWidgetInfo) => {
    setLayoutStatic(widget, false);
  }
  const onRemoveWidget = (widget: DashboardWidgetInfo) => {
    const widgetIndex = findIndex(widgets, (w: any) => w.layout.i === widget.layout.i);
    if (widgetIndex !== -1) {
      widgets.splice(widgetIndex, 1);
      const newWidgets = [...widgets];
      setWidgets(newWidgets);
    }
  }
  const getWidgetComponent = (widgetName: string) => {
    if (widgetName === 'PieChartWidget') { //可以改成策略
      return (<React.Suspense fallback={<WidgetLoadingSpin/>}>
        <PieChartWidgetLazy/>
      </React.Suspense>);
    } else {
      return (<React.Suspense fallback={<WidgetLoadingSpin/>}>
        <BarChartWidgetLazy/>
      </React.Suspense>);
    }
  }
  const createWidget = (widget: DashboardWidgetInfo) => {
    return (
      <div className={'dashboard-widget-wrapper'} key={widget.layout.i} data-grid={widget.layout}>
          <span className='dashboard-widget-header'>
            <QuestionCircleOutlined className={'dashboard-widget-header-icon'}/>
            {widget.layout.static ? <LockOutlined className={'dashboard-widget-header-icon'} onClick={() => unlockWidget(widget)}/> : (
              <UnlockOutlined className={'dashboard-widget-header-icon'} onClick={() => lockWidget(widget)}/>)}
            <CloseOutlined className={'dashboard-widget-header-icon'} onClick={() => onRemoveWidget(widget)}/>
          </span>
        {getWidgetComponent(widget.widgetName)}
      </div>
    );
  }
  const onAddWidget = () => {
    const x = (widgets.length * 3) % 12;
    const widgetName = x % 2 == 0 ? 'BarChartWidget' : 'PieChartWidget'
    const newWidgets = [...widgets, {
      widgetName: widgetName,
      layout: {i: uniqueId(widgetName), x: x, y: Infinity, w: 3, h: 2, static: false}
    }] as DashboardWidgetInfo[];
    setWidgets(newWidgets);
  }
  const onLayoutChange = (layouts: any[]) => {
    for (const layout of layouts) {
      const updateIndex = findIndex(widgets, (w) => w.layout.i === layout.i);
      if (updateIndex !== -1) {
        const updateWidget = widgets[updateIndex];
        updateWidget.layout = {
          ...layout,
        };
        widgets.splice(updateIndex, 1, {...updateWidget});
      }
    }
    const newWidgets = [...widgets];
    setWidgets(newWidgets);
  }
  return (
    <>
      <Button onClick={onAddWidget}>add widget</Button>
      <ReactGridLayout
        cols={12}
        rowHeight={100}
        autoSize={true}
        isDraggable={true}
        isResizable={true}
        isBounded={true}
        layout={getLayouts()}
        className={'layouts'}
        onLayoutChange={onLayoutChange}>
        {widgets?.map(item => createWidget(item))}
      </ReactGridLayout>
    </>
  );
}
export default DashboardGird

最终效果可以看到,当我们侧栏(抽屉)移动时并不会自动帮我们调整react-grid-layout中元素的占位,也就是在最右边我们可以看到,当侧栏(抽屉)隐藏的时候,最右边是有空白的,并不会自适应填充。

请添加图片描述

那其实在官网中给出了解决方案:https://github.com/react-grid-layout/react-grid-layout

Have a more complicated layout? WidthProvider is very simple and only listens to window ‘resize’ events. If you need more power and flexibility, try the SizeMe React HOC as an alternative to WidthProvider.

react-grid-layout中提供的WidthProvider只是很简单的监听了浏览器窗口’resize’的事件,根本没办法监听到当前容器大小更变的事件,所以我们需要react-sizeme来帮助我们知道当前容器的大小

所以我们需要首先npm install react-sizeme,然后我们就可以使用了。这里就不过多介绍如何使用,直接给出解决的代码

解决代码

import React, {useState} from "react";
import 'react-grid-layout/css/styles.css'
import 'react-resizable/css/styles.css'
import {Button} from "antd";
import {findIndex, uniqueId} from "lodash";
import './dashboard.css'
import WidgetLoadingSpin from "@/pages/Dashboard/Detail/WidgetLoadingSpin";
import {CloseOutlined, LockOutlined, QuestionCircleOutlined, UnlockOutlined} from "@ant-design/icons";
import ReactGridLayout from "react-grid-layout";
import {cloneDeep} from "lodash-es";
import {withSize} from 'react-sizeme';
const BarChartWidgetLazy = React.lazy(() => import('@/pages/Dashboard/Detail/Widget/BarChartWidget'));
const PieChartWidgetLazy = React.lazy(() => import('@/pages/Dashboard/Detail/Widget/PieChartWidget'));
interface DashboardWidgetInfo {
  widgetName: string,
  layout: ReactGridLayout.Layout
}
function DashboardGird({ size: { width } }: any) {
  const [widgets, setWidgets] = useState<DashboardWidgetInfo[]>([]);
  const getLayouts: any = () => {
    return cloneDeep(widgets.map(item => item.layout));
  }
  const setLayoutStatic = (widget: DashboardWidgetInfo, staticFlag: boolean) => {
    const index = findIndex(widgets, (w: any) => w.widgetName === widget.widgetName);
    if (index !== -1) {
      const updateWidget = widgets[index];
      updateWidget.layout.static = staticFlag;
      widgets.splice(index, 1, {...updateWidget});
      const newWidgets = [...widgets];
      setWidgets(newWidgets);
    }
  }
  const lockWidget = (widget: DashboardWidgetInfo) => {
    setLayoutStatic(widget, true);
  }
  const unlockWidget = (widget: DashboardWidgetInfo) => {
    setLayoutStatic(widget, false);
  }
  const onRemoveWidget = (widget: DashboardWidgetInfo) => {
    const widgetIndex = findIndex(widgets, (w: any) => w.layout.i === widget.layout.i);
    if (widgetIndex !== -1) {
      widgets.splice(widgetIndex, 1);
      const newWidgets = [...widgets];
      setWidgets(newWidgets);
    }
  }
  const getWidgetComponent = (widgetName: string) => {
    if (widgetName === 'PieChartWidget') { //可以改成策略
      return (<React.Suspense fallback={<WidgetLoadingSpin/>}>
        <PieChartWidgetLazy/>
      </React.Suspense>);
    } else {
      return (<React.Suspense fallback={<WidgetLoadingSpin/>}>
        <BarChartWidgetLazy/>
      </React.Suspense>);
    }
  }
  const createWidget = (widget: DashboardWidgetInfo) => {
    return (
      <div className={'dashboard-widget-wrapper'} key={widget.layout.i} data-grid={widget.layout}>
          <span className='dashboard-widget-header'>
            <QuestionCircleOutlined className={'dashboard-widget-header-icon'}/>
            {widget.layout.static ? <LockOutlined className={'dashboard-widget-header-icon'} onClick={() => unlockWidget(widget)}/> : (
              <UnlockOutlined className={'dashboard-widget-header-icon'} onClick={() => lockWidget(widget)}/>)}
            <CloseOutlined className={'dashboard-widget-header-icon'} onClick={() => onRemoveWidget(widget)}/>
          </span>
        {getWidgetComponent(widget.widgetName)}
      </div>
    );
  }
  const onAddWidget = () => {
    const x = (widgets.length * 3) % 12;
    const widgetName = x % 2 == 0 ? 'BarChartWidget' : 'PieChartWidget'
    const newWidgets = [...widgets, {
      widgetName: widgetName,
      layout: {i: uniqueId(widgetName), x: x, y: Infinity, w: 3, h: 2, static: false}
    }] as DashboardWidgetInfo[];
    setWidgets(newWidgets);
  }
  const onLayoutChange = (layouts: any[]) => {
    for (const layout of layouts) {
      const updateIndex = findIndex(widgets, (w) => w.layout.i === layout.i);
      if (updateIndex !== -1) {
        const updateWidget = widgets[updateIndex];
        updateWidget.layout = {
          ...layout,
        };
        widgets.splice(updateIndex, 1, {...updateWidget});
      }
    }
    const newWidgets = [...widgets];
    setWidgets(newWidgets);
  }
  return (
    <div>
      <Button onClick={onAddWidget}>add widget</Button>
      <ReactGridLayout
        cols={12}
        rowHeight={100}
        width={width}
        autoSize={true}
        isDraggable={true}
        isResizable={true}
        isBounded={true}
        layout={getLayouts()}
        className={'layouts'}
        onLayoutChange={onLayoutChange}>
        {widgets?.map(item => createWidget(item))}
      </ReactGridLayout>
    </div>
  );
}
export default withSize({ refreshMode: 'debounce', refreshRate: 60 })(DashboardGird);

接下来我们来看看效果

请添加图片描述

这样我们就通过react-sizeme解决react-grid-layout中侧栏(抽屉)移动时不会调整大小的问题了

参考

react-sizeme: 让你的React Components知道它们的宽度和高度!

Tired of Boring Static Dashboards? Let’s Build a Fully Customizable Dashboard in React

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/47150.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

postgres源码解析38 表创建执行全流程梳理--2

本小节主要讲解查询执行模块&#xff0c;有机地调用存储、索引、事务、并发等模块&#xff0c;按照执行计划中的计划节点&#xff08;操作执行接口&#xff09;完成数据的读取或者修改。知识回顾&#xff1a;postgres源码解析37 表创建执行全流程梳理–1 关键数据结构 总图&a…

八、【React-Router5】路由组件传参

文章目录1、实现效果2、向路由组件传递参数总览3、修改上一节代码3.1、项目结构变更如下3.2、CODE&#xff08;params传参&#xff09;3.2.1、Messages.jsx3.2.2、Detail.jsx3.2.3、Result3.3、CODE&#xff08;search传参&#xff09;3.3.1、Messages.jsx3.3.2、Detail.jsx3.3…

【强化学习论文】小样本策略泛化的提示决策转换器

文献题目&#xff1a;Prompting Decision Transformer for Few-Shot Policy Generalization 摘要 人类可以利用先前的经验并从少量演示中学习新任务。与旨在通过更好的算法设计实现快速适应的离线元强化学习相比&#xff0c;我们研究了架构归纳偏差对少样本学习能力的影响。我…

RationalDMIS2022车削件(轴类)测量:回转体检测

1.坐标系知识 在三坐标测量机的使用中,坐标系的建立是最为关键的一步,是工件测量的基本依据。设备在组装本身中有着XYZ三个互相垂直的坐标轴,因此坐标系的建立便是通过以工件上的特征作为依据建立XYZ三个互相垂直的坐标轴与设备的坐标轴进行对应,从而使程序得以运行。 物…

虚拟机安装

虚拟机安装 能看到这里说明你的电脑中已经安装的有虚拟机了&#xff0c;如果没有虚拟机可以先下载安装一些虚拟机。 有了虚拟机后首先要准备的就是镜像&#xff0c;我用的是CentOS-7。如果没有的也可以百度或者去阿里云下载即可。 选择下载以ISO结尾的文件&#xff0c;可选类型…

SLAM学习笔记(二)

5.相机与图像 相机将三维世界中的坐标点&#xff08;单位米&#xff09;映射到二维图像平面&#xff08;单位为像素&#xff09;的过程中能够用一个几何模型进行描述。 单目相机(Mono)的成像过程&#xff1a; 1、世界坐标系下有个固定的点P&#xff0c;世界坐标为 2、由于相…

关于quartus 13.1出现的问题的一些总结

1&#xff0c;如果IP核的版本与当前的quartus ii版本不一致的情况&#xff0c;有时候虽然能编译成功&#xff0c;但是无法修改原有工程的IP核参数设置。 如&#xff1a; 之前我下载的工程用到的NCO IP核是12.1 version的&#xff0c;但是我用到的quartus 版本是13.0和13.1&am…

led灯什么牌子的质量好?2022双十二家用护眼台灯推荐

台灯作为一种晚上或者其他黑暗条件下的照明灯具&#xff0c;对于经常熬夜的人群来说可以说是必备工具了&#xff0c;无论是看书、写字&#xff0c;还是工作、学习&#xff0c;都非常实用&#xff0c;它不同于平常的家用的室内照明顶灯&#xff0c;光线不会那么刺眼&#xff0c;…

uni-app入门:小程序UI组件Vant Weapp

1.vant介绍 2.安装步骤 2.1 通过 npm 安装 2.2 修改 app.json 2.3 修改 project.config.json 2.4 构建 npm 包 3.使用说明 1.vant介绍Vant Weapp 是一个轻量、可靠的移动端组件库&#xff0c;于 2017 年开源,是由有赞前端团队开…

Mysql 安装与卸载

MySQL8.0.26-Linux版安装 文章目录MySQL8.0.26-Linux版安装1. 安装1.1 准备一台Linux服务器1.2. 下载Linux版MySQL安装包1.3. 上传MySQL安装包1.4. 创建目录,并解压1.5. 安装mysql的安装包1.6. 启动MySQL服务1.7. 查询自动生成的root用户密码1.8. 修改root用户密码1.9. 创建用户…

【FRP】群晖docker中部署Frp

2022-08-24 by 崔斐然 0&#xff1a;需求 公司有台笔记本&#xff0c;现在疫情期间居家办公。我用的MacBook RDP客户端做的非常好用&#xff0c;如相互粘贴文件、文字等&#xff0c;MacBook通过远程桌面连接公司内网电脑会比较方便&#xff0c;时延和体验感远优于向日葵。之前…

java成神之路-基础篇 (搞定java基础看这一篇就够用)

java成神之路-基础篇 文章目录java成神之路-基础篇[toc]01面向对象**→ 什么是面向对象**→ 平台无关性→ 值传递1、什么是[值传递](https://so.csdn.net/so/search?q值传递&spm1001.2101.3001.7020)&#xff0c;什么是引用传递&#xff1f;2.值传递和[引用传递](https://…

23软考备考已开始,网络工程师知识点速记~

新一轮软考备考来啦~ 为了帮助大家提高备考效率&#xff0c;将2023上半年软考网络工程师知识点速记分享给大家&#xff0c;快来跟着一起打卡学习吧&#xff01; 进制的转换 数据的表示方法有二进制、八进制、十进制和十六进制等。网络工程师考试要求重点掌握这四种进制之间的…

mysql基础知识篇(六)

1.如何分库&#xff1f; 垂直分库&#xff1a;以表为依据&#xff0c;按照业务归属不同&#xff0c;将不同的表拆分到不同的库中。 水平分库&#xff1a;以字段为依据&#xff0c;按照一定策略&#xff08;hash、range 等&#xff09;&#xff0c;将一个库中的数据拆分到多个库…

线代 | 【提神醒脑】自用笔记串联三 —— 相似对角化 · 二次型 · 合同变换

本文总结参考于 kira 2023 线代提神醒脑技巧班。 笔记均为自用整理。加油!ヾ(◍∇◍)ノ゙ 九、相似对角化 9.1、矩阵相似的性质 ----------------------------------------------------------------------------------------------------------…

Linux 网络编程项目 —— FTP 网盘

文章目录项目简介知识点描述项目功能指令远程功能指令本地功能指令使用的关键函数access 函数popen 函数chdir 函数strtok 函数strncmp 函数linux system函数是否执行成功判断方法基本流程服务端客户端FTP代码实例头文件 ftp.h客户端 client.c服务端 server.cV2.0版 – 启用副服…

如何实现虹科物联网HMI/网关的调度器功能?

一、前言 JMobile软件提供了一个调度器引擎&#xff0c;通过设定的时间计划表自动执行特定动作&#xff0c;从而赋予HMI/网关调度器功能&#xff0c;减少现场操作人员的工作压力。本文主要介绍如何实现JMobile软件的调度器功能。 二、工具 1. Windows PC 2. JMobile Studio…

《论文阅读》DeepSFM: Structure From Motion Via Deep Bundle Adjustment

留个笔记自用 DeepSFM: Structure From Motion Via Deep Bundle Adjustment 做什么 首先是最基础的&#xff0c;Structure-from-Motion&#xff08;SFM&#xff09;&#xff0c;SFM可以简单翻译成运动估计&#xff0c;是一种基于dui8序列图片进行三维重建的算法。简单来说就…

C++11(三)可变模板参数、lambda表达式、包装器

&#x1f9f8;&#x1f9f8;&#x1f9f8;各位大佬大家好&#xff0c;我是猪皮兄弟&#x1f9f8;&#x1f9f8;&#x1f9f8; 文章目录一、可变模板参数1.通过递归推导参数包2.通过列表初始化推导参数包二、emplace三、lambda表达式1.lambda表达式语法2.使用lambda3.捕捉列表说…

phpstorm+wamp在线调试wordpress

简介 本文源自公司内部使用wordpress搭建了一套官网&#xff0c;经常有定制化的需求&#xff0c;有些插件实现不了&#xff0c;需要通过phpstorm调试的方式熟悉wordpress&#xff0c;同时修改php代码&#xff0c;本地测试环境window&#xff0c;适合用wamp作为php运行环境&…