[英]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: 'a', x: 0, y: 0, w: 1, h: 2}
在这个库中,我需要创建像{ {i: 'a', x: 0, y: 0, w: 1, h: 2}
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"
}
]
}
] ]
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>
</>
);
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.