简体   繁体   English

如何使用 react-grid-layout 创建动态拖放布局

[英]How to create dynamic drag and drop layout with react-grid-layout

I am using react-grid-layout to make drag-drop and resize components , So i am able to achieve the functionality as mentioned in the doc.我正在使用react-grid-layout进行drag-drop and resize components ,因此我能够实现文档中提到的功能。

My Issue我的问题

  • I am creating dynamic UI so I am rendering my UI with data.我正在创建动态 UI,所以我正在用数据渲染我的 UI。
  • Here in this library I need to create layout like { {i: 'a', x: 0, y: 0, w: 1, h: 2}在这个库中,我需要创建像{ {i: 'a', x: 0, y: 0, w: 1, h: 2}
  • When I am creating static UI I am able to achieve what I want.当我创建 static UI 时,我能够实现我想要的。 Here is working code sandbox 这是工作代码沙箱

In static Ui with predefined layout I did like below.在具有预定义布局的 static Ui 中,我如下所示。

    const layout = [
    { i: "a", x: 0, y: 0, w: 2, h: 1 },
    { i: "b", x: 2, y: 0, w: 2, h: 1 },
    { i: "c", x: 4, y: 0, w: 2, h: 1 },
    { i: "d", x: 6, y: 0, w: 2, h: 1 },
    { i: "e", x: 0, y: 2, w: 2, h: 1 }
  ];

<div className="App">
  <GridLayout
    className="layout"
    layout={layout}
    style={{ backgroundColor: "blue" }}
  >
    {layout.map((li) => (
      <div key={li.i} style={{ backgroundColor: "yellow" }}>
        {li.i}
      </div>
    ))}
  </GridLayout>

This is working fine, But here the layout I have defined is static, So for this I searched and got one example with dynamic height and width, which is creating a dynamic layout.这工作正常,但这里我定义的布局是 static,所以为此我搜索并获得了一个动态高度和宽度的示例,它正在创建动态布局。

But that is creating the layout with just random numbers which is not showing up with my UI (as per my use), This is what I found out in library for dynamic UI但这只是用我的 UI 中没有显示的随机数创建布局(根据我的使用), 这是我在动态 UI 库中发现的

What I am trying to do我想要做什么

I have this data as in my state我的 state 中有这些数据

const [data1, setData] = useState({
    EmpData: [
        {
            empId: 11,
            lay1: { i: 'a' },
            data: [
                {
                    firstName: 'Steve',
                    lastName: 'Smith',
                },
                {
                    firstName: 'Michel',
                    lastName: 'Muner',
                },
            ],
        },
        {
            empId: 12,
            lay1: { i: 'b' },
            data: [
                {
                    firstName: 'Charles',
                    lastName: 'Johnsen',
                },
                {
                    firstName: 'Glen',
                    lastName: 'Tyson',
                },
            ],
        },
        {
            empId: 13,
            lay1: { i: 'c' },
            data: [
                {
                    firstName: 'Steve',
                    lastName: 'Smith',
                },
                {
                    firstName: 'Michel',
                    lastName: 'Muner',
                },
            ],
        },
        {
            empId: 14,
            lay1: { i: 'd' },
            data: [
                {
                    firstName: 'Steve',
                    lastName: 'Smith',
                },
                {
                    firstName: 'Michel',
                    lastName: 'Muner',
                },
            ],
        },
        {
            empId: 15,
            lay1: { i: 'e' },
            data: [
                {
                    firstName: 'Steve',
                    lastName: 'Smith',
                },
                {
                    firstName: 'Michel',
                    lastName: 'Muner',
                },
            ],
        },
    ],
});

By above data I am creating Ui as per my need通过上述数据,我正在根据需要创建 Ui

return data1.EmpData.map((li, index) => (
        <div key={index.toString()} data-grid={index}"> </div> //what should I pass here as key and layout that I am not getting
            <>
                {li.data.map((l) => (
                    <>
                        <div>{l.firstName}</div>
                        <div>{l.lastName}</div>
                    </>
                ))}
            </>
        </div>
    ));
};

Passing key and creating dynamic layout is where I am not able to figure out how can I achieve this, as this is totally new thing to me.传递key和创建动态layout是我无法弄清楚如何实现这一点的地方,因为这对我来说是全新的事情。

My UI is totally dynamic Every time I am going to get dynamic data so that much cards or divs I need to show.我的 UI 是完全动态的 每次我要获取动态数据时,我需要显示很多卡片或 div。

Here is my code sand box what I am trying to do dynamically 这是我正在尝试动态执行的代码沙盒

Edit / Update编辑/更新

The answer I got from @Daniil Loban is very helpfull, but when I am trying to loop with my real time data it is looping twice, That is hapenning because my data is little bit different of what I have shown here我从@Daniil Loban得到的答案非常有帮助,但是当我尝试循环使用我的实时数据时,它会循环两次,这是因为我的数据与我在这里显示的有点不同

Actually I am not able to understand I use data1.EmpData[li] to get data to display when I map layout.实际上我无法理解I use data1.EmpData[li] to get data to display when I map layout. this line.这条线。

My data我的数据

    [
{
  compId: 5,
  company_name: "Info",
  comp_data: [
    {
      empId: 1,
      empName:"steve"
    },
    {
      empId: 2,
      empName:"meg"
    }
  ]
},
{
  compId: 6,
  company_name: "wipro",
  comp_data: [
    {
      empId: 11,
      empName:"mark"
    },
    {
      empId: 12,
      empName:"Tnml"
    }
  ]
}

] ]

  • How data goes is like company->employ of that company->data of that company,数据的走向就像公司->该公司的雇员->该公司的数据,
  • So here company can be multiple employ can be multiple similarly for data所以这里的公司可以是多个雇员,也可以是多个类似的数据
  • What i have updated in previous data I have not mentioned the company as I thought of writing minimal code.我在以前的数据中更新的内容我没有提到公司,因为我想编写最少的代码。
  • I have added full code Now and Here is my code sandbox我现在添加了完整的代码, 这是我的代码沙箱

The issue问题

  • Issue is it is repeating the data, I am getting duplicate data on display问题是重复数据,我正在显示重复数据

  • I ll explain here like company namme->companydata->employe name this should be the perfect but what is happening is -- companyname->the in one div both employ I a, getting and in other again I am getting both ones我将在这里解释,例如company namme->companydata->employe name ,这应该是完美的,但正在发生的事情是——公司名称->在一个 div 中都雇用了我,得到和在另一个我得到了两个

这是显示错误数据的图像

It should be for Info there are two employ so in one grid one employ and in other one the other employ.对于Info来说,应该有两个雇员,所以在一个网格中一个雇员,另一个网格中另一个雇员。

The issue is in generateDOM this function as layout is generated perfectly but in one Layout it is repeating all then same for others, if lenght is 3 then it is creating 3 layouts which is totally fine, but inside one layout it is agian looping and showing duplicate data问题出在generateDOM这个 function 中,因为布局是完美生成的,但在一个布局中,它对其他布局重复所有相同,如果长度为 3,那么它正在创建 3 个布局,这完全没问题,但在一个布局中,它是 agian 循环和显示重复数据

Here by I am attaching one image how it should show on UI在这里,我附上了一张图片,它应该如何在 UI 上显示这就是我想要实现的目标

I think the problem was that layout was not used, I also noticed the incorrect use of random from lodash (but this is not essential)我认为问题在于没有使用布局,我还注意到从 lodash 中随机使用不正确(但这不是必需的)

I use data1.EmpData[li] to get data to display when I map layout .当我使用 map layout时,我使用data1.EmpData[li]来获取要显示的数据。

I also created a sandbox where there is a button for dynamic addition, I think this is what you wanted.我还创建了一个沙箱,其中有一个用于动态添加的按钮,我认为这就是您想要的。

  const generateDOM = () => {
    // Generate items with properties from the layout, rather than pass the layout directly
    const layout = generateLayout();
    return _.map(layout, function (l) {
      return (
        <div key={l.i} data-grid={l} className="bg-success">
          <>
            <div className="rounded" key="?"></div>
            {data1.EmpData[l.i].data.map((l) => (
              <>
                <div>{l.firstName}</div>
                <div>{l.lastName}</div>
              </>
            ))}
          </>
        </div>
      );
    });
  };

For updated question:对于更新的问题:

在此处输入图像描述

  const generateDOM = (lo) => {
    // Generate items with properties from the layout, rather than pass the layout directly
    const layout = generateLayout();
    return _.map(layout, function (l) {
      return (
        <div key={l.i} data-grid={l} className="bg-success">
          <div>{lo[l.i].empName}</div>
          {console.log(lo, l, active_menu)}
        </div>
      );
    });
  };

And when we render, we don't need map , but just one call:当我们渲染时, we don't need map ,只需要一个电话:

  return (
    <>
      {data1.map((d, ind) => (
        <div className={ind === active_menu ? "compNameActive" : "compName"}>
          <p onClick={() => compClick(ind)}>{d.company_name}</p>
        </div>
      ))}
      <ReactGridLayout onLayoutChange={onLayoutChange} {...props}>
        {generateDOM(data1[active_menu].comp_data)}
      </ReactGridLayout>
    </>
  );

sanbox2 sanbox2

The layout should be an object containing the layout data, including an id i to store the relation to other data:布局应该是一个包含布局数据的 object,包括一个 id i来存储与其他数据的关系:

[
    { i: "a", x: 0, y: 0, w: 2, h: 1 },
          ^------- The id to store the relation to other data
]

You need to build the layout first, either in a way that you choose, or directly from your emp-data.您需要首先以您选择的方式或直接从您的 emp-data 构建布局。 Only the id i has to match your emp-data, the other values are "independant" layout data.只有id i必须与您的 emp-data 匹配,其他值是“独立”布局数据。

Note that my example requires the empId to be unique (there is duplication in your example).请注意,我的示例要求empId是唯一的(您的示例中有重复)。

Eg:例如:

const generateLayout = () => {
  let totalIndex = -1;
  return data1.EmpData.reduce( (accEmp, empItem, empIndex) => {
    return accEmp.concat(
      empItem.data.map( (dataItem, index) => {
        const w = _.random(1, 2);
        const h = _.random(1, 3);
        totalIndex++;
        return {
          x: (totalIndex * 2) % 12,
          y: Math.floor(totalIndex / 6),
          w: w,
          h: h,
          i: empItem.empId + '-' + index
        };
      })
    );
  }, []);
}

Then, to display the content, you can iterate over the layout data, and find the elements to display by the id i stored in the layout.然后,要显示内容,您可以遍历布局数据,并通过存储在布局中的i查找要显示的元素。 Eg:例如:

const generateDOM = () => {
  const layout = generateLayout();

  return layout.map((ly, index) => {
    const [ empIndex, dataIndex ] = ly.i.split('-');

    const empItem = data1.EmpData.find( eI => eI.empId.toString() === empIndex );
    const dataItem = empItem.data[ dataIndex ];

    return (
      <div key={ly.i} className="bg-success">
        <div className="rounded" key="?"></div>
        <>
          <div>{dataItem.firstName}</div>
          <div>{dataItem.lastName}</div>
        </>
      </div>
    );
  });
};

I think you can also do it the other way around, ie iterate over your emp-data, and find the matching layout item.我认为您也可以反过来做,即遍历您的 emp 数据,并找到匹配的布局项。 But I'm not sure.但我不确定。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM