我正在用存储信息的卡制作Trello板。 我有3个重要组成部分来进行此操作:
TrelloBoard.js-包含5个属于div的车道。它还存储所有卡。
Lanes.js-是仅在视觉上容纳卡片的div
Cards.js-包含信息,可以拖动到其他通道
在TrellBoard.js中,我的卡如下存储在状态内:
cards: [ [], [], [], [], []],
此刻,每个组件的状态都保持跟踪它在[0-4]中的哪一列以及[0+]列中的位置
当我将一张卡从一个车道拖到另一个车道时,Card.js中的onDragStart方法存储位置(列-车道X -以及列-位置Y < / strong>),然后一旦将其放到车道上,就会调用Lane.js中的onDrop(...)方法,该方法使TrelloBoard.js知道我正在使用 lane X 移动卡片位置Y ,到Z线的最后一个位置
在TrelloBoard中,我现在将卡从纸牌阵列中拼接起来,并通过transferCards(...)方法将其移动到另一个位置:
初始:
0 1 2 3 4
-----
一次移动
0-2 3 4
--1--
现在,如果我像这样将Card 2从第三列移动到第二列:
失败
0 2 1 3 4
-----
我的卡1内的状态认为它位于位置(1)而不是显示的位置(0)。这是因为我移动了卡2之后,第3列中的其余卡(即第一张图中的卡1)没有更新其状态,该状态包含其索引。
我本以为可以在TrelloBoard.js中管理有关卡的所有数据,但是一旦我集成了矿石的复杂数据,例如截止日期,描述,状态甚至是化身……它就变得太复杂了,无法在内部进行管理TrelloBoard.js,我更愿意管理每个单独组件中的所有数据。
所以目前我还很想弄清楚如何管理卡
我还不太熟悉React,但是我想我可以将引用附加到已创建的每张卡上,并从TrelloBoard.js中拼接和更新card []数组的方法中,我可以在每个Card中(在受影响的列中)调用每个方法,这些方法将在列中移动其位置/索引(例如,诸如shiftDown(){this.setState({index:this.index-1})})和从TrelloBoard.js调用它
TrelloBoard.js
import React, { Component } from 'react';
import './TrelloBoard.css';
import Card from '../components/Lane/Card';
import Lane from '../components/Lane/Lane';
import Modal from '../components/UI/Modal/Modal';
import Axios from 'axios';
class TrelloBoard extends Component {
constructor(props) {
super(props);
this.child = React.createRef();
}
state = {
cardModal: false,
modalTitle: "default",
modalStatus: "default",
modalStatusNumber: -1,
cards: [ [], [], [], [], []], // this should actually be lanes - thought
lanes: [],
testInit: false
}
setModalTitle = (name) => {
this.setState({modalTitle : name});
}
setModalStatus = (status) => {
this.setState({modalStatus : status})
}
closeModalHandler = () => {
this.setState({cardModal : false});
}
cardClickedHandler = (name, col) => {
this.setModalTitle(name);
this.setModalStatus(this.titles[col]);
this.setState({modalStatusNumber: col})
this.openModalHandler();
}
openModalHandler = () => {
this.setState({cardModal : true});
}
titles = ['Open', 'In progress', 'To be tested', 'Re-opened', 'Closed'];
colors = ['open', 'progress', 'test', 'reopened', '
componentDidMount() {
this.initCards();
}
initCards() {
if (!this.state.testInit) {
let initCards = [ [], [], [], [], []];
let initLanes = [];
let i = 0;
let n = 0;
for (const t of this.titles) {
n = 0;
const keyName = i+"-"+n;
const card = (<Card clicked = {this.cardClickedHandler}
ref={this.child}
keyID = {keyName}
column={i} >Column {i} card</Card>);
initCards[i].push(card);
const lane = (<Lane color={this.colors[i]} columnNumber={i}
title = {t} transfer={this.transferCards}>
{card}
</Lane>);
initLanes.push(lane);
i++;
}
this.setState({ cards: [...initCards] });
this.setState({ lanes: [...initLanes] });
this.setState({ testInit: true});
}
}
transferCards = (dragStartColumn, dragStartIndex, dragDestinationColumn, name) => {
const tempCards = [...this.state.cards];
// const spliced
tempCards[dragStartColumn].splice(dragStartIndex, 1);
// now all the cards after this one will have the incorrect position so we will have to update them all
// but then I don't have access to the rest of the data in the lane after that... damn!
const keyName = dragDestinationColumn+"-"+(tempCards[dragDestinationColumn].length);
const newCard = (<Card clicked = {this.cardClickedHandler}
keyID = {keyName} ref={this.child} index={tempCards[dragDestinationColumn].length-1}
column={dragDestinationColumn} name={name}>{name}</Card>);
tempCards[dragDestinationColumn].push(newCard);
// THIS IS WHAT I HAVE IN MIND!
// for (const c of tempCards[dragStartColumn]) {
// c.child.shiftDown();
// }
// alert("col: " + dragDestinationColumn + " | item: " + (tempCards[dragDestinationColumn].length-1) +
// " | destCol: " + dragDestinationColumn);
// spliced[0] needs to update its column index
const tempLanes = [...this.state.lanes];
const i = dragStartColumn;
const originalLane = (<Lane color={this.colors[i]} columnNumber={i}
title = {this.titles[i]} transfer={this.transferCards}>
{tempCards[dragStartColumn]}
</Lane>);
const d = dragDestinationColumn;
const destinationLane = (<Lane color={this.colors[d]} columnNumber={d}
title = {this.titles[d]} transfer={this.transferCards}>
{tempCards[dragDestinationColumn]}
</Lane>);
// problem 2 lines tempCards[..]..
alert(tempCards[2].length);
tempLanes[dragStartColumn] = originalLane;
tempLanes[dragDestinationColumn] = destinationLane;
this.setState( { cards: tempCards });
this.setState( { lanes: tempLanes });
// alert(array.length + " nuber of columns");
}
render () {
return (
<div className="wrapper">
{this.state.lanes}
<Modal
show = {this.state.cardModal} modalClosed = {this.closeModalHandler}
status={this.state.modalStatus} title={this.state.modalTitle}
color={this.state.modalStatusNumber} >
</Modal>
</div>
);
}
}
export default TrelloBoard;
Lane.js
import React, { Component } from 'react';
import './Lane.css';
import LaneContents from './LaneContents';
import LaneTitle from './LaneTitle';
import Space from './Space';
class Lane extends Component {
state = {
columnNumber: -1
}
onDragOver(ev) {
ev.preventDefault();
}
onDrop(ev, cat) {
let id = ev.dataTransfer.getData("id");
let name = ev.dataTransfer.getData("name");
const draggedCardColumn = id.split("-");
if (+draggedCardColumn[0] === this.state.columnNumber) {
return alert("dragging and dropping to same col");
}
// let TrelloBoard know to remove the card and put it in the other column
alert("col: " + +draggedCardColumn[0] + " | item: " + +draggedCardColumn[1] + " | destCol:" + +this.state.columnNumber);
this.props.transfer(+draggedCardColumn[0], +draggedCardColumn[1], this.state.columnNumber, name);
}
componentDidMount() {
this.setState({ columnNumber: this.props.columnNumber })
}
render() {
return (
<div className= "box"
onDrop={(e)=>{this.onDrop(e, "wip")}}
onDragOver={(e) => this.onDragOver(e)}>
<LaneTitle color={this.props.color}>{this.props.title}</LaneTitle>
<Space/>
<LaneContents>
{this.props.children}
</LaneContents>
</div>
);
}
};
export default Lane;
Card.js
import React, { Component } from 'react';
import './Card.css';
class Card extends Component {
state = {
column: 2,
index: -1,
name: "default"
}
componentDidMount() {
this.setState({column: this.props.column});
this.setState({title: this.props.children});
this.setState({index: this.props.index});
this.setState({name: this.props.name});
}
onDragEnd = (ev) => {
ev.preventDefault();
}
onDragStart = (ev, id) => {
console.log('dragstart:',id);
ev.dataTransfer.setData("id", id);
ev.dataTransfer.setData("name", this.props.children);
}
updateIndex(newIndex) {
this.setState({ index: newIndex });
}
shiftDown() {
// THIS IS WHAT I HAVE IN MIND - to be called from TrelloBoard.js
// this.setState({ index: this.state.index - 1});
}
updateColumn(newColumn) {
this.setState({ column: newColumn });
}
setTitle() {
this.setState({ title: this.props.children})
}
render() {
return (
<div
key = {this.props.keyID}
className="box-contents--card droppable"
draggable="true"
onClick = {() => this.props.clicked(this.props.children, this.state.column) }
onDragStart = {(e) => this.onDragStart(e, this.props.keyID)}
onDragEnd = {(e) => this.onDragEnd(e)}
>
{this.props.children}
</div>
);
}
};
export default Card;