JavaScript 拖放 - 拖动副本

问题描述 投票:0回答:1

我正在尝试创建一个强大的拖放事件调度程序。我几乎已经完成了所有内容,但卡在一个元素上:如何拖动项目的副本。

您可以在这里看到当前运行的版本:jsfiddle

我希望能够发生的是:

  1. 当将 LeadIn 事件从“事件”列拖到“屏幕”列时,原始的 LeadIn 事件应保留在“事件”列中。
  2. 当将 LeadIn 事件从屏幕列拖动到另一个屏幕列时,该事件应移动到新列。
  3. 当将 LeadIn 事件从屏幕列拖动到事件列时,该事件应从屏幕列中删除,并且不会出现在事件列中。
  4. “事件”列中应始终只有一个 LeadIn 事件。

任何帮助将不胜感激。

另外,这是我当前的代码:

HTML:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Sortable Event Scheduler</title>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="css/styles.css">
</head>
<body>
    <div class="container">
        <div class="column" id="events">
            <div class="column-header">Events</div>
            <ul class="sortable-list">
                <li class="event" data-duration="00:15:00">
                    <div class="event-title">Welcome</div>
                    <div class="event-start-time"></div>
                    <div class="event-duration">Duration: 00:15:00</div>
                    <div class="event-end-time"></div>
                </li>
                <li class="event lead-in-event leadin-event" id="leadIn" data-duration="00:01:00" data-event-type="">
                    <div class="event-title">LeadIn</div>
                    <div class="event-start-time" style="display: none;"></div>
                    <div class="event-duration" style="display: none;">Duration: 00:01:00</div>
                    <div class="event-end-time" style="display: none;"></div>
                </li>
                <li class="event" data-duration="00:05:10">
                    <div class="event-title">Film 1</div>
                    <div class="event-start-time"></div>
                    <div class="event-duration">Duration: 00:05:10</div>
                    <div class="event-end-time"></div>
                </li>
                <li class="event" data-duration="00:09:40">
                    <div class="event-title">Film 2</div>
                    <div class="event-start-time"></div>
                    <div class="event-duration">Duration: 00:09:40</div>
                    <div class="event-end-time"></div>
                </li>
            </ul>
        </div>
        <div class="column" id="friday-screen-1" data-start-time="18:00:00">
            <div class="column-header">Friday - Screen 1</div>
            <ul class="sortable-list">
                <!-- Add events here -->
            </ul>
            <div class="column-total-duration"></div>
        </div>
        <div class="column" id="saturday-screen-1" data-start-time="08:30:00">
            <div class="column-header">Saturday - Screen 1</div>
            <ul class="sortable-list">
                <!-- Add events here -->
            </ul>
            <div class="column-total-duration"></div>
        </div>
        <div class="column" id="saturday-screen-2" data-start-time="08:30:00">
            <div class="column-header">Saturday - Screen 2</div>
            <ul class="sortable-list">
                <!-- Add events here -->
            </ul>
            <div class="column-total-duration"></div>
        </div>
        <div class="column" id="sunday-screen-1" data-start-time="08:30:00">
            <div class="column-header">Sunday - Screen 1</div>
            <ul class="sortable-list">
                <!-- Add events here -->
            </ul>
            <div class="column-total-duration"></div>
        </div>
        <div class="column" id="sunday-screen-2" data-start-time="08:30:00">
            <div class="column-header">Sunday - Screen 2</div>
            <ul class="sortable-list">
                <!-- Add events here -->
            </ul>
            <div class="column-total-duration"></div>
        </div>
    </div>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js"></script>
    <script src="js/moment.js"></script>
    <script src="js/script.js"></script>
</body>
</html>


CSS:

body {
    font-family: 'Open Sans', sans-serif;
    font-size: 14px;
}

.container {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    padding: 20px;
}

.column {
    width: calc(16.666% - 10px); /* Equal width for 6 columns with 10px gap */
    border: 1px solid #ddd;
    padding: 10px;
}

.column-header {
    font-weight: bold;
    margin-bottom: 10px;
}

.sortable-list {
    list-style: none;
    padding: 0;
    min-height: 50px;
}

.event {
    background-color: #3498db;
    color: white;
    padding: 5px;
    margin: 5px 0;
    cursor: pointer;
}

.event-duration, .event-start-time, .event-end-time {
    font-size: 12px;
}

.event-placeholder {
    background-color: #ddd;
    height: 20px;
    margin: 5px 0;
}

.event-title {
    font-weight: bold;
}

.total-duration {
    color: #666;
    font-size: 12px;
}


JAVASCRIPT:

$(document).ready(function () {
    // Call the sort function on page load to alphabetize the Events column
    sortEventsInEventsColumn();

    $(function() {
        $(".sortable-list").sortable({
            connectWith: ".sortable-list",
            placeholder: "event-placeholder",
            receive: function (event, ui) {
                var $targetColumn = $(this).closest(".column");

                if ($targetColumn.attr("id") !== "events") {
                    // Recalculate start and end times for the entire column
                    recalculateColumnTimes($targetColumn);

                    // Update total duration for the target column
                    updateTotalDuration($targetColumn);
                } else {
                    // Clear start and end times for the dragged event item
                    updateEventTimes(ui.item, "", "");
                }

                // Sort events in the Events column
                sortEventsInEventsColumn();
            },
            update: function (event, ui) {
                var $targetColumn = $(this).closest(".column");

                if ($targetColumn.attr("id") !== "events") {
                    // Recalculate start and end times for the entire column
                    recalculateColumnTimes($targetColumn);

                    // Update total duration for the target column
                    updateTotalDuration($targetColumn);
                } else {
                    // Clear start and end times for the moved event item
                    updateEventTimes(ui.item, "", "");
                }

                // Sort events in the Events column
                sortEventsInEventsColumn();
            },
            remove: function (event, ui) {
                var $sourceColumn = $(this).closest(".column");
                if ($sourceColumn.attr("id") !== "events") {
                    // Recalculate start and end times for the entire column
                    recalculateColumnTimes($sourceColumn);

                    // Update total duration for the source column
                    updateTotalDuration($sourceColumn);
                }

                // Sort events in the Events column
                sortEventsInEventsColumn();
            }
        }).disableSelection();
    });

    function recalculateColumnTimes($column) {
        var $events = $column.find(".event");
        var startTime = $column.data("start-time");

        $events.each(function (index) {
            var $event = $(this);
            var duration = $event.data("duration");
            var endTime = calculateEndTime(startTime, duration);

            // Update start and end times for the event
            updateEventTimes($event, "Start: " + formatTimeAMPM(startTime), "End: " + formatTimeAMPM(endTime));

            // Update startTime for the next event
            startTime = endTime;
        });
    }

    function updateEventTimes($event, startTime, endTime) {
        $event.find(".event-start-time").text(startTime);
        $event.find(".event-end-time").text(endTime);
    }

    function calculateEndTime(startTime, duration) {
        var start = moment(startTime, "HH:mm:ss");
        var dur = moment.duration(duration);
        var end = start.clone().add(dur);
        return end.format("HH:mm:ss");
    }

    function formatTimeAMPM(time) {
        return moment(time, "HH:mm:ss").format("h:mm:ss A");
    }

    function sortEventsInEventsColumn() {
        var $eventsColumn = $("#events");
        var $eventList = $eventsColumn.find(".sortable-list");
        var events = $eventList.children(".event").get();

        events.sort(function (a, b) {
            var titleA = $(a).find(".event-title").text();
            var titleB = $(b).find(".event-title").text();

            // Move the "LeadIn" event to the top of the list
            if (titleA === "LeadIn") {
                return -1; // "LeadIn" comes before other events
            } else if (titleB === "LeadIn") {
                return 1; // Other events come after "LeadIn"
            }

            // Sort other events alphabetically
            return titleA.localeCompare(titleB);
        });

        $.each(events, function (index, event) {
            $eventList.append(event);
        });
    }

    function updateTotalDuration($column) {
        var $eventList = $column.find(".sortable-list");
        var totalDuration = moment.duration();

        $eventList.find(".event").each(function () {
            var duration = moment.duration($(this).data("duration"));
            totalDuration.add(duration);
        });

        var formattedTotalDuration = formatDuration(totalDuration);
        $column.find(".column-total-duration").text("Total Duration: " + formattedTotalDuration);
    }

    function formatDuration(duration) {
        var hours = duration.hours();
        var minutes = duration.minutes();
        return hours + "h " + minutes + "m";
    }
});
javascript jquery jquery-ui drag-and-drop
1个回答
0
投票

灵感来自 https://jqueryui.com/draggable/#sortable(结合排序和拖动的示例):jsFiddle

$(".sortable-list").sortable({
    connectWith: ".sortable-list",
    placeholder: "event-placeholder",
    items: "> :not('#leadIn')",
    receive: function (event, ui) {            
        var $targetColumn = $(this).closest(".column");

        if (ui.item.hasClass("lead-in-event")) {
            if ($targetColumn.attr("id") === "events") {
                ui.item.remove();
            } else {
                ui.item.siblings(".lead-in-event").remove();
            }
        }
$("#leadIn").draggable({
    connectToSortable: ".column:not(#events) .sortable-list:not(:has(.lead-in-event))",
    helper: "clone"
});

未定义将 LeadIn 事件从屏幕列拖动到已包含 LeadIn 事件的另一个屏幕列时会发生什么。此实现从源屏幕列中删除了 LeadIn 事件。

注意:此实现不会尝试更新时间簿记代码。

© www.soinside.com 2019 - 2024. All rights reserved.