我希望能够将可拖动框拖放到任何其他日期,并且它应该删除前一个日期。 例如,如果我将拖动框从 3 月 5 日移动到 3 月 6 日,它应该从 3 月 5 日删除并更新到 3 月 6 日 我的问题是,当我拖放此框时,它显示一个停止标志,我无法移动它。有什么方法可以修复它或任何其他方法,以便我可以将我的框及其数据移动到另一个日期(当您将鼠标悬停在拖动框上时,有一些数据名称和 subrub 吗?
我的 runsheetpreview.js 代码
import React, { useState, useRef } from "react";
import { startOfMonth, endOfMonth, startOfWeek, endOfWeek, format, addDays, addMonths, subMonths, isSameMonth } from "date-fns";
import "../assets/css/RunSheetPDF.css";
const DraggableBox = ({ day, onDrop, name: initialName, suburb: initialSuburb }) => {
const [editable, setEditable] = useState(false);
const [name, setName] = useState(initialName);
const [suburb, setSuburb] = useState(initialSuburb);
const [showTooltip, setShowTooltip] = useState(false);
const boxRef = useRef(null);
const handleDoubleClick = () => {
setEditable(true);
};
const handleChangeName = (e) => {
setName(e.target.value);
};
const handleChangeSuburb = (e) => {
setSuburb(e.target.value);
};
const handleBlur = () => {
setEditable(false);
};
const handleDragStart = () => {
setShowTooltip(false);
boxRef.current.classList.add('dragging');
};
const handleDragEnd = () => {
boxRef.current.classList.remove('dragging');
};
const handleDragOver = (e) => {
e.preventDefault();
};
const handleDrop = (e) => {
e.preventDefault();
const draggedDay = parseInt(e.dataTransfer.getData("text/plain"));
onDrop(draggedDay, day);
};
return (
<div
className="drag-box"
ref={boxRef}
draggable
onDragStart={handleDragStart}
onDragEnd={handleDragEnd}
onDoubleClick={handleDoubleClick}
onDragOver={handleDragOver}
onDrop={handleDrop}
onMouseEnter={() => setShowTooltip(true)}
onMouseLeave={() => setShowTooltip(false)}
style={{
width: "70px",
height: "80px",
textAlign: "center",
backgroundColor: "#F5F5F5",
color: "#333333",
marginTop: "5px",
position: "relative",
cursor: "move" // Set cursor to move when hovering over the box
}}
>
<p style={{ margin: 0, lineHeight: "80px" }}>{day}</p>
{showTooltip && (
<div className="tooltip">
<p>Name: {name}</p>
<p>Suburb: {suburb}</p>
</div>
)}
</div>
);
};
const RunSheetPreview = () => {
const [selectedDate, setSelectedDate] = useState(new Date());
const [calendarData, setCalendarData] = useState([
{ day: 5, name: "John", suburb: "Suburb 1" },
{ day: 15, name: "Alice", suburb: "Suburb 2" },
{ day: 25, name: "Bob", suburb: "Suburb 3" },
{ day: 27, name: "Eva", suburb: "Suburb 4" }
]);
const handleDrop = (draggedDay, dropDay) => {
const newData = [...calendarData];
const draggedItem = newData.find(item => item.day === draggedDay);
draggedItem.day = dropDay;
setCalendarData(newData);
};
const generateCalendar = () => {
const monthStart = startOfMonth(selectedDate);
const monthEnd = endOfMonth(selectedDate);
const startDate = startOfWeek(monthStart, { weekStartsOn: 0 });
const endDate = endOfWeek(monthEnd, { weekStartsOn: 0 });
const rows = [];
let days = [];
let day = startDate;
while (day <= endDate) {
for (let i = 0; i < 7; i++) {
const dayOfMonth = format(day, "d");
const isCurrentMonth = isSameMonth(day, monthStart);
const draggableData = calendarData.find(item => item.day === parseInt(dayOfMonth));
const draggableBoxExists = draggableData !== undefined;
days.push(
<td key={day} style={{ width: "70px", height: "80px" }}>
{isCurrentMonth && (
<div>
{draggableBoxExists ? (
<DraggableBox
day={draggableData.day}
name={draggableData.name}
suburb={draggableData.suburb}
onDrop={handleDrop}
/>
) : (
<p>{dayOfMonth}</p>
)}
</div>
)}
</td>
);
day = addDays(day, 1);
}
rows.push(<tr key={day}>{days}</tr>);
days = [];
}
return rows;
};
const handleNextMonth = () => {
setSelectedDate(addMonths(selectedDate, 1));
};
const handlePreviousMonth = () => {
setSelectedDate(subMonths(selectedDate, 1));
};
return (
<div style={{ width: "100%", display: "flex", flexDirection: "column", alignItems: "center", marginTop: "20px" }}>
<div style={{ display: "flex", alignItems: "center", justifyContent: "center", marginBottom: "0px" }}>
<button onClick={handlePreviousMonth} style={{ backgroundColor: "#F5F5F5", color: "#333333", border: "1px solid #CCCCCC", borderRadius: "5px", padding: "5px 10px", marginRight: "10px" }}>Previous Month</button>
<h2 style={{ color: "#333333", margin: 0 }}>{format(selectedDate, "MMMM yyyy")}</h2>
<button onClick={handleNextMonth} style={{ backgroundColor: "#F5F5F5", color: "#333333", border: "1px solid #CCCCCC", borderRadius: "5px", padding: "5px 10px", marginLeft: "10px" }}>Next Month</button>
</div>
<div className="calendar-container">
<table className="calendar-table">
<thead>
<tr>
<th>Sun</th>
<th>Mon</th>
<th>Tue</th>
<th>Wed</th>
<th>Thu</th>
<th>Fri</th>
<th>Sat</th>
</tr>
</thead>
<tbody>
{generateCalendar()}
</tbody>
</table>
</div>
</div>
);
};
export default RunSheetPreview;
我的 RunSheetPDF.css 代码
.centered-text {
text-align: center;
font-weight: 700;
}
.title {
text-align: left;
font-weight: bold;
font-size: 30px;
text-transform: uppercase;
font-style: bold;
}
.table-container {
width: 1000px;
background: white;
font-family: "Times New Roman";
}
.table {
width: 90%;
border-collapse: collapse;
}
.top-header th {
text-align: left;
border: none;
}
.table-body td {
text-align: left;
border: none;
}
.paper {
padding: 20px;
display: flex;
justify-content: space-between;
}
.left-content {
flex: 1;
text-align: left;
}
.right-content {
flex: 1;
text-align: left;
}
.flex-content {
display: flex;
justify-content: space-between;
}
.empty-box {
text-align: left;
}
.border-box {
width: 100px;
height: 20px;
border: 1px solid #000;
}
.bold-text {
font-weight: bold;
}
.normal-text {
font-weight: normal;
}
.text-left {
text-align: left;
font-family: "Times New Roman", Times, serif;
}
.no-border {
border: none;
}
.page-content {
height: 38rem;
overflow: auto;
border: solid 1px black;
margin: 0 80mm 30mm 45mm;
width: 35rem;
page-break-after: always;
}
/* Use media query to apply styles only when printing */
@media print {
.page-content {
page-break-before: always; /* This will force a page break before each .page-content element */
}
}
/* Add this to your CSS file or CSS module */
.print-button-wrapper {
position: fixed;
bottom: 130px; /* Adjust this value to change the vertical position */
right: 150px; /* Adjust this value to change the horizontal position */
}
.calendar-container {
margin: 20px auto;
max-width: 800px;
background-color: #f2f2f2;
padding: 20px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.calendar-table {
width: 100%;
border-collapse: collapse;
}
.calendar-table th, .calendar-table td {
padding: 10px;
text-align: center;
border: 2px solid #fff; /* White border to separate cells */
}
.calendar-table th {
background-color: #3f51b5; /* Dark blue background for days */
color: #fff;
font-weight: bold;
font-size: 18px;
}
.calendar-table td {
background-color: #ffffff; /* White background for date cells */
}
.calendar-table td:first-child {
background-color: #f5f5f5; /* Light gray background for first column */
}
.drag-box {
padding: 10px;
border: 1px solid #ccc;
background-color: #fff;
cursor: pointer;
}
.drag-box p {
margin: 5px 0;
}
.drag-box input {
width: 100%;
padding: 5px;
margin-bottom: 5px;
}
.drag-box.draggable {
background-color: #ffd700; /* Gold background for draggable box */
border-color: #ffd700;
color: #000;
}
.drag-box.draggable p {
color: #000;
}
.drag-box {
background-color: #ffffff;
border: 1px solid #cccccc;
border-radius: 5px;
padding: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
width: 100px; /* Adjust the width as needed */
height: 60px; /* Adjust the height as needed */
transition: opacity 0.3s ease; /* Add transition for smooth hide/show effect */
}
.drag-box.hidden {
opacity: 0; /* Hide the box during drag */
}
.calendar-table {
border-collapse: collapse;
width: 100%; /* Make the table fill its container */
background-color: #f0e8ff; /* Light purple background color */
}
.calendar-table th,
.calendar-table td {
border: 1px solid #cccccc;
padding: 8px;
text-align: center;
width: 100px; /* Adjust the width of table cells */
}
.drag-box {
cursor: pointer;
border: 1px solid #ccc;
border-radius: 5px;
padding: 5px;
margin: 2px;
}
.calendar-table {
width: 100%;
}
.calendar-table td {
border: 1px solid #ccc;
padding: 5px;
text-align: center;
}
.calendar-table p {
margin: 0;
}
.drag-box {
cursor: pointer;
border: 1px solid #ccc;
border-radius: 5px;
padding: 5px;
margin: 2px;
position: relative; /* Add relative positioning */
}
.tooltip {
position: absolute;
top: 100%; /* Position below the draggable box */
left: 50%; /* Center horizontally */
transform: translateX(-50%); /* Center horizontally */
background-color: #fff;
border: 1px solid #ccc;
border-radius: 5px;
padding: 5px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
z-index: 1; /* Ensure tooltip appears above other elements */
white-space: nowrap; /* Prevent line breaks */
visibility: hidden; /* Initially hidden */
}
.drag-box:hover .tooltip {
visibility: visible; /* Show tooltip on hover */
}
所以,我对您的代码做了一些更改。所以我想要理解的是,首先,如果我将一个可拖动框拖到其他框上(比如说第 5 个框超过第 15 个框,那么第 15 个框中的任何数据都将被第 5 个框数据替换,之后第 5 个框数据也将被删除),所以对于我已将一些附加状态作为道具传递给可拖动框组件(calenddarData、changeName、changeDay、changeSuburb states)。 然后在 Draggablebox 组件中声明的handleDragStart 和handleDrop 函数也都被更新。在handleDragStart中,每当开始拖动时,我都会将拖动的元素数据保存在changeName、changeDay、changeSuburb状态中。 然后在handleDrop中,我首先检查拖动的元素是否在同一日期被删除,如果不是,那么我只是更新calendarData。解决了第一个问题。 现在,对于第二个问题,即在没有自己的可拖动框的日期上放置可拖动框(例如在第 6 个日期拖动第 5 个框),使用相同的逻辑,只是我已将handleDragStart、handDrop、handleDragOver 传递给 p 标记。您应该在 RunSheetPreview 组件中定义这些函数。由于这些组件被重用,您可以将它们作为 props 传递给 Draggable box 组件。
import { useState, useRef } from "react";
import { startOfMonth, endOfMonth, startOfWeek, endOfWeek, format, addDays, addMonths, subMonths, isSameMonth } from "date-fns";
import "./RunSheetPDF.css";
const DraggableBox = ({ day, name: initialName, suburb: initialSuburb, calendarData, setCalendarData,
changeName, setChangeName, changeSuburb, setChangeSuburb, setChangeDay, changeDay }) => {
//eslint-disable-next-line
const [editable, setEditable] = useState(false);
const [name, setName] = useState(initialName);
const [suburb, setSuburb] = useState(initialSuburb);
const [showTooltip, setShowTooltip] = useState(false);
const boxRef = useRef(null);
const handleDoubleClick = () => {
setEditable(true);
};
//eslint-disable-next-line
const handleChangeName = (e) => {
setName(e.target.value);
};
//eslint-disable-next-line
const handleChangeSuburb = (e) => {
setSuburb(e.target.value);
};
//eslint-disable-next-line
const handleBlur = () => {
setEditable(false);
};
const handleDragStart = () => {
setShowTooltip(false);
setChangeName(initialName);
setChangeSuburb(initialSuburb)
setChangeDay(day)
boxRef.current.classList.add('dragging');
};
const handleDragEnd = () => {
boxRef.current.classList.remove('dragging');
};
const handleDragOver = (e) => {
e.preventDefault();
};
const handleDrop = (e) => {
e.preventDefault();
e.stopPropagation();
if(Number(changeDay) !== Number(e.target.innerText)){
const newData = {
day: Number(e.target.innerText),
name: changeName,
suburb: changeSuburb,
}
const newCalData = [...calendarData];
const calData = newCalData.filter((f) => Number(f.day) !== Number(e.target.innerText) && Number(f.day) !== Number(changeDay) );
calData.push(newData);
calData.sort((a,b) => Number(a.day) - Number(b.day))
setCalendarData(calData)
setChangeDay(null);
setChangeName(null);
setChangeSuburb(null);
}
};
return (
<div
className="drag-box"
ref={boxRef}
draggable
onDragStart={handleDragStart}
onDragEnd={handleDragEnd}
onDoubleClick={handleDoubleClick}
onDragOver={handleDragOver}
onDrop={handleDrop}
onMouseEnter={() => setShowTooltip(true)}
onMouseLeave={() => setShowTooltip(false)}
style={{
width: "70px",
height: "80px",
textAlign: "center",
backgroundColor: "#F5F5F5",
color: "#333333",
marginTop: "5px",
position: "relative",
cursor: "move" // Set cursor to move when hovering over the box
}}
>
<p style={{ margin: 0, lineHeight: "80px" }}>{day}</p>
{showTooltip && (
<div className="tooltip">
<p>Name: {initialName}</p>
<p>Suburb: {initialSuburb}</p>
</div>
)}
</div>
);
};
const RunSheetPreview = () => {
const [selectedDate, setSelectedDate] = useState(new Date());
const [calendarData, setCalendarData] = useState([
{ day: 5, name: "John", suburb: "Suburb 1" },
{ day: 15, name: "Alice", suburb: "Suburb 2" },
{ day: 25, name: "Bob", suburb: "Suburb 3" },
{ day: 27, name: "Eva", suburb: "Suburb 4" }
]);
const boxRef = useRef(null);
const [changeName, setChangeName] = useState("");
const [changeDay, setChangeDay] = useState(null);
const [changeSuburb, setChangeSuburb] = useState(null);
const handleDragStart = () => {
setShowTooltip(false);
setChangeName(initialName);
setChangeSuburb(initialSuburb)
setChangeDay(day)
boxRef.current.classList.add('dragging');
};
const handleDragOver = (e) => {
e.preventDefault();
};
const handleDrop = (e) => {
e.preventDefault();
e.stopPropagation();
if(Number(changeDay) !== Number(e.target.innerText)){
const newData = {
day: Number(e.target.innerText),
name: changeName,
suburb: changeSuburb,
}
const newCalData = [...calendarData];
const calData = newCalData.filter((f) => Number(f.day) !== Number(e.target.innerText) && Number(f.day) !== Number(changeDay) );
calData.push(newData);
calData.sort((a,b) => Number(a.day) - Number(b.day))
setCalendarData(calData)
setChangeDay(null);
setChangeName(null);
setChangeSuburb(null);
}
};
const generateCalendar = () => {
const monthStart = startOfMonth(selectedDate);
const monthEnd = endOfMonth(selectedDate);
const startDate = startOfWeek(monthStart, { weekStartsOn: 0 });
const endDate = endOfWeek(monthEnd, { weekStartsOn: 0 });
const rows = [];
let days = [];
let day = startDate;
while (day <= endDate) {
for (let i = 0; i < 7; i++) {
const dayOfMonth = format(day, "d");
const isCurrentMonth = isSameMonth(day, monthStart);
const draggableData = calendarData.find(item => item.day === parseInt(dayOfMonth));
const draggableBoxExists = draggableData;
days.push(
<td key={day} style={{ width: "70px", height: "80px" }}>
{isCurrentMonth && (
<div
>
{draggableBoxExists ? (
<DraggableBox
day={draggableData.day}
name={draggableData.name}
suburb={draggableData.suburb}
setCalendarData={setCalendarData}
calendarData={calendarData}
changeName={changeName}
setChangeName={setChangeName}
changeDay={changeDay}
setChangeDay={setChangeDay}
changeSuburb={changeSuburb}
setChangeSuburb={setChangeSuburb}
/>
) : (
<p
style={{
height: "100px",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
ref={boxRef}
onDragStart={handleDragStart}
onDragOver={handleDragOver}
onDrop={handleDrop}
>
{dayOfMonth}
</p>
)}
</div>
)}
</td>
);
day = addDays(day, 1);
}
rows.push(<tr key={day}>{days}</tr>);
days = [];
}
return rows;
};
const handleNextMonth = () => {
setSelectedDate(addMonths(selectedDate, 1));
};
const handlePreviousMonth = () => {
setSelectedDate(subMonths(selectedDate, 1));
};
return (
<div style={{ width: "100%", display: "flex", flexDirection: "column", alignItems: "center", marginTop: "20px" }}>
<div style={{ display: "flex", alignItems: "center", justifyContent: "center", marginBottom: "0px" }}>
<button onClick={handlePreviousMonth} style={{ backgroundColor: "#F5F5F5", color: "#333333", border: "1px solid #CCCCCC", borderRadius: "5px", padding: "5px 10px", marginRight: "10px" }}>Previous Month</button>
<h2 style={{ color: "#333333", margin: 0 }}>{format(selectedDate, "MMMM yyyy")}</h2>
<button onClick={handleNextMonth} style={{ backgroundColor: "#F5F5F5", color: "#333333", border: "1px solid #CCCCCC", borderRadius: "5px", padding: "5px 10px", marginLeft: "10px" }}>Next Month</button>
</div>
<div className="calendar-container">
<table className="calendar-table">
<thead>
<tr>
<th>Sun</th>
<th>Mon</th>
<th>Tue</th>
<th>Wed</th>
<th>Thu</th>
<th>Fri</th>
<th>Sat</th>
</tr>
</thead>
<tbody>
{generateCalendar()}
</tbody>
</table>
</div>
</div>
);
};
export default RunSheetPreview;