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

问题描述

我使用 react-grid-layout 来制作 drag-drop and resize components,所以我能够实现文档中提到的功能

我的问题

  • 我正在创建动态 UI,因此我正在使用数据渲染我的 UI。
  • 在这个库中,我需要创建布局,如 { {i: 'a',x: 0,y: 0,w: 1,h: 2}
  • 当我创建静态 UI 时,我能够实现我想要的。Here is working code sandbox

在具有预定义布局的静态 UI 中,我喜欢下面的内容

    const layout = [
    { i: "a",w: 2,h: 1 },{ i: "b",x: 2,{ i: "c",x: 4,{ i: "d",x: 6,{ i: "e",y: 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 what I found out in library for dynamic UI

我想做什么

我有这个数据,就像我的状态

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' },{
            empId: 14,lay1: { i: 'd' },{
            empId: 15,lay1: { i: 'e' },});

根据以上数据,我根据需要创建了 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>
    ));
};

传递 key 并创建动态 layout 是我无法弄清楚如何实现这一点的地方,因为这对我来说是全新的事情。

我的 UI 是完全动态的每次我要获取动态数据时,我都需要显示很多卡片或 div。

Here is my code sand box what I am trying to do dynamically

编辑/更新

我从 @Daniil Loban 得到的答案非常有帮助,但是当我尝试使用实时数据进行循环时,它会循环两次,这是因为我的数据与我的数据略有不同已在此处显示

实际上我无法理解 I use data1.EmpData[l.i] to get data to display when I map layout. 这一行。

我的数据

    [
{
  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"
    }
  ]
}

]

  • 数据的流向就像公司->该公司的雇员->该公司的数据,
  • 所以这里的公司可以是多个员工,数据也可以是多个类似的
  • 我在之前的数据中更新了什么 我没有提到这家公司,因为我想到的是编写最少的代码
  • 我现在添加了完整代码Here is my code sandbox

问题

  • 问题是重复数据,我显示重复数据

  • 我会像 company namme->companydata->employe name 这样解释,这应该是完美的,但正在发生的事情是 -- companyname->在一个 div 中都使用了 I a,在另一个 div 中,我同时获得了两个

Here is the image which is showing wrong data

应该是 Info 有两个雇用,所以在一个网格中一个雇用一个,另一个雇用另一个

问题出在 generateDOM 这个函数中,因为布局是完美生成的,但是在一个布局中,它对其他布局重复所有然后相同,如果 lenght 是 3,那么它正在创建 3 个布局,这完全没问题,但在一个布局中,它再次循环并显示重复数据

在这里附上一张图片,它应该如何在 UI 上显示

This is whaqt I am trying to achieve

解决方法

我认为问题在于没有使用布局,我还注意到 lodash 中 random 的使用不正确(但这不是必需的)

当我映射 data1.EmpData[l.i] 时,我使用 layout 获取要显示的数据。

我还创建了一个 sandbox,其中有一个用于动态添加的按钮,我认为这正是您想要的。

  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>
      );
    });
  };

对于更新的问题:

enter image description here

  const generateDOM = (lo) => {
    // Generate items with properties from the 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>
      );
    });
  };

当我们渲染时,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

,

布局应该是一个包含布局数据的对象,包括一个 id i 来存储与其他数据的关系:

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

您需要首先以您选择的方式或直接从您的 emp-data 构建布局。只有 id i 必须匹配您的 emp-data,其他值是“独立”布局数据。

请注意,我的示例要求 empId 是唯一的(您的示例中有重复)。

例如:

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
        };
      })
    );
  },[]);
}

然后,要显示内容,您可以遍历 layout 数据,并通过存储在布局中的 id i 找到要显示的元素。 例如:

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>
    );
  });
};

我认为你也可以反过来做,即迭代你的 emp-data,并找到匹配的布局项。但我不确定。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...