如何使用 react-grid-layout 创建动态拖放布局
How to create dynamic drag and drop layout with 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", 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>
这工作正常,但这里我定义的布局是静态的,因此为此我搜索并获得了一个具有动态高度和宽度的示例,它正在创建一个动态布局。
但这只是用随机数创建布局,我的 UI(根据我的使用)、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' },
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',
},
],
},
],
});
根据以上数据,我正在根据需要创建 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
这应该是完美的,但发生的事情是 -- 公司名称->合二为一 div 都雇用了我,得到和在另一个我又得到了两个
应该是Info
有两个雇员,所以在一个网格中一个雇员,另一个雇员。
问题出在generateDOM
这个函数中,因为布局是完美生成的,但在一个布局中,它重复所有内容,然后对其他布局相同,如果长度为 3,则它正在创建 3 个布局,这完全没问题,但在一个布局中它是 agian 循环并显示重复数据
我在这里附上一张图片,它应该如何显示在 UI
布局应该是一个包含布局数据的对象,包括一个 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,找到匹配的布局项。但我不确定。
我认为问题是没有使用布局,我也注意到 lodash 中随机使用不正确(但这不是必需的)
我使用 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>
);
});
};
更新后的问题:
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>
);
});
};
当我们渲染时,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>
</>
);
我正在使用 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", 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>
这工作正常,但这里我定义的布局是静态的,因此为此我搜索并获得了一个具有动态高度和宽度的示例,它正在创建一个动态布局。
但这只是用随机数创建布局,我的 UI(根据我的使用)、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' },
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',
},
],
},
],
});
根据以上数据,我正在根据需要创建 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
这应该是完美的,但发生的事情是 -- 公司名称->合二为一 div 都雇用了我,得到和在另一个我又得到了两个
应该是Info
有两个雇员,所以在一个网格中一个雇员,另一个雇员。
问题出在generateDOM
这个函数中,因为布局是完美生成的,但在一个布局中,它重复所有内容,然后对其他布局相同,如果长度为 3,则它正在创建 3 个布局,这完全没问题,但在一个布局中它是 agian 循环并显示重复数据
我在这里附上一张图片,它应该如何显示在 UI
布局应该是一个包含布局数据的对象,包括一个 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,找到匹配的布局项。但我不确定。
我认为问题是没有使用布局,我也注意到 lodash 中随机使用不正确(但这不是必需的)
我使用 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>
);
});
};
更新后的问题:
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>
);
});
};
当我们渲染时,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>
</>
);