You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP+HTML实现7天三餐唯一元素选择交互方案求助

问题描述

我正在开发基于PHP和HTML的界面,需为7天的早、中、晚三餐各从21个唯一元素列表中选择元素,要求选中元素从其他下拉菜单移除或设置为不可选状态,且选中元素需与对应日期关联。目前无法实现选中元素的移除效果,现附上我的View代码,寻求可行解决方案,同时希望了解是否有比下拉菜单更简便的替代组件。

原始View代码

<section class="intro container">
    <div class="row">
        <div class="span12">
            <p>Seleziona i piatti che vuoi inserire nel tuo menù settimanale. Puoi selezionare fino a 7 piatti per ogni pasto della giornata.</p>

            <?php
            $startDate = new DateTime($assegnazioneMemory->data);
            $endDate = new DateTime($assegnazioneMemory->data_fine);
            $endDate->modify('+1 day'); // Include the end date in the period
            $interval = new DateInterval('P1D');
            $period = new DatePeriod($startDate, $interval, $endDate);
            $numeroColazioni = new DatePeriod($startDate, $interval, $endDate);
            $giorni = array('Domenica', 'Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato');
            ?>

            <form action="<?= base_url('questo-poi-lo-vediamo') ?>" method="post">

                <table class="table table-bordered text-center">
                    <thead>
                        <tr>
                            <th>Giorno</th>
                            <th>Colazione</th>
                            <th>Pranzo</th>
                            <th>Cena</th>
                        </tr>
                    </thead>
                    <tbody>
                        <?php $i = 1; ?>
                        <?php foreach ($period as $date) :
                        ?>
                            <tr>
                                <td> <?php $dayNumber = date("w", strtotime($date->format('Y-m-d')));
                                        $dayName = $giorni[$dayNumber];
                                        $extendedDate = date("d", strtotime($date->format('Y-m-d')));
                                        echo "$dayName $extendedDate";
                                        ?>
                                    <input type="hidden" name="data<?= $i ?>" value="<?= $date->format('Y-m-d') ?>">
                                </td>
                                <td>
                                    <select class="form-select" id="colazione">
                                        <option selected>Seleziona colazione <?= $i ?></option>

                                        <?php
                                        $a = 0;
                                        foreach ($numeroColazioni as $giorno) {
                                            $a++; ?>
                                            <option carboidrati='
                                            <?php
                                            if (${'colazione' . $a}->alimento_1_c == 1 || ${'colazione' . $a}->alimento_2_c == 1 || ${'colazione' . $a}->alimento_3_c == 1 || ${'colazione' . $a}->alimento_4_c == 1) {
                                                echo "1";
                                            } else {
                                                echo "0";
                                            }
                                            ?>' value='<?= strval($programmaMemory->{'colazione' . $a . '_id'}) ?>'><?= strval($programmaMemory->{'colazione' . $a}) ?></option>;;
                                        <?php
                                        }
                                        ?>
                                    </select>
                                </td>
                                <td>
                                    <select class="form-select" id="pranzo">
                                        <option selected>Seleziona pranzo <?= $i ?></option>
                                        <?php
                                        $a = 0;
                                        foreach ($numeroColazioni as $giorno) {
                                            $a++; ?>
                                            <option carboidrati='
                                            <?php
                                            if (${'pranzo' . $a}->alimento_1_c == 1 || ${'pranzo' . $a}->alimento_2_c == 1 || ${'pranzo' . $a}->alimento_3_c == 1 || ${'pranzo' . $a}->alimento_4_c == 1) {
                                                echo "1";
                                            } else {
                                                echo "0";
                                            }
                                            ?>' value='<?= strval($programmaMemory->{'pranzo' . $a . '_id'}) ?>'><?= strval($programmaMemory->{'pranzo' . $a}) ?></option>;;
                                        <?php
                                        }
                                        ?>
                                    </select>
                                </td>
                                <td>
                                    <select class="form-select" id="cena">
                                        <option selected>Seleziona cena <?= $i ?></option>
                                        <?php
                                        $a = 0;
                                        foreach ($numeroColazioni as $giorno) {
                                            $a++; ?>
                                            <option carboidrati='
                                            <?php
                                            if (${'cena' . $a}->alimento_1_c == 1 || ${'cena' . $a}->alimento_2_c == 1 || ${'cena' . $a}->alimento_3_c == 1 || ${'cena' . $a}->alimento_4_c == 1) {
                                                echo "1";
                                            } else {
                                                echo "0";
                                            }
                                            ?>' value='<?= strval($programmaMemory->{'cena' . $a . '_id'}) ?>'><?= strval($programmaMemory->{'cena' . $a}) ?></option>;;
                                        <?php
                                        }
                                        ?>
                                    </select>
                                </td>
                            </tr>
                        <?php $i++;
                        endforeach;
                        ?>
                    </tbody>
                </table>

            </form>
        </div>

</section>
解决方案

一、实现选中元素的禁用/移除功能

1. 先修正HTML结构问题

你当前代码里所有同类型下拉菜单的id都是重复的(比如所有早餐下拉都用id="colazione"),这会导致JS无法精准定位元素。首先给每个下拉菜单设置唯一ID,比如按日期和餐型命名:id="colazione-<?= $i ?>",同时添加通用类meal-select方便JS批量操作。

修改后的下拉菜单示例:

<select class="form-select meal-select" id="colazione-<?= $i ?>" data-day="<?= $i ?>">
    <option selected>Seleziona colazione <?= $i ?></option>
    <!-- 原有选项内容不变 -->
</select>

2. 用JavaScript实现选中项同步禁用

添加一段原生JS代码,监听所有下拉菜单的选择变化,记录已选中的餐品ID,然后遍历所有下拉菜单,将已选中的值对应的选项设置为不可选,同时处理取消选择的情况(恢复禁用状态)。

// 存储已选中的所有餐品ID
const selectedMeals = new Set();
// 获取所有餐品选择下拉
const allSelects = document.querySelectorAll('.meal-select');

// 初始化:如果有默认选中项,先加入集合
allSelects.forEach(select => {
    const selectedValue = select.value;
    if (selectedValue && selectedValue !== '') {
        selectedMeals.add(selectedValue);
    }
});

// 更新所有下拉菜单的禁用状态
function updateDisabledOptions() {
    allSelects.forEach(select => {
        Array.from(select.options).forEach(option => {
            // 排除默认提示选项,已选中的选项在当前下拉保留,其他下拉禁用
            if (option.value && selectedMeals.has(option.value) && option.value !== select.value) {
                option.disabled = true;
            } else {
                option.disabled = false;
            }
        });
    });
}

// 初始化执行一次
updateDisabledOptions();

// 监听下拉菜单变化事件
allSelects.forEach(select => {
    select.addEventListener('change', function() {
        // 移除之前选中的值(如果存在)
        const oldValue = this.dataset.previousValue || '';
        if (oldValue) {
            selectedMeals.delete(oldValue);
        }
        // 添加新选中的值
        const newValue = this.value;
        if (newValue) {
            selectedMeals.add(newValue);
        }
        // 存储当前选中值,用于下次变化时移除
        this.dataset.previousValue = newValue;
        // 更新所有下拉的禁用状态
        updateDisabledOptions();
    });
});

3. 后端验证(必须做)

前端的禁用只是用户体验优化,恶意用户可以绕过前端限制提交重复值。所以在PHP处理表单的方法中,必须收集所有选中的餐品ID,检查是否有重复:

// 示例:收集所有选中的餐品ID
$selectedIds = [];
for ($i = 1; $i <= 7; $i++) {
    $colazioneId = $_POST["colazione-$i"] ?? '';
    $pranzoId = $_POST["pranzo-$i"] ?? '';
    $cenaId = $_POST["cena-$i"] ?? '';
    
    if ($colazioneId) $selectedIds[] = $colazioneId;
    if ($pranzoId) $selectedIds[] = $pranzoId;
    if ($cenaId) $selectedIds[] = $cenaId;
}

// 检查是否有重复
if (count($selectedIds) !== count(array_unique($selectedIds))) {
    // 返回错误提示,比如"不能选择重复餐品"
    header("Location: {$_SERVER['HTTP_REFERER']}?error=duplicate");
    exit;
}

二、更简便的替代组件推荐

如果觉得下拉菜单操作繁琐,可以考虑以下几种组件:

  • 拖拽选择组件:把21个餐品做成可拖拽的卡片,用户直接拖拽到对应日期的三餐位置,操作直观。可以用原生JS的drag/drop事件实现,或者用轻量库SortableJS简化开发。
  • 侧边餐品列表+点击分配:在页面侧边展示所有未分配的餐品,用户点击餐品后选择对应的日期和餐型,系统自动将餐品填充到表格对应位置并从侧边列表移除。
  • 单选按钮组+过滤:每个餐品对应一个单选按钮,旁边标注可分配的日期/餐位,用户选择后自动标记已分配,同时隐藏已选餐品。适合21个餐品这种数量不多的场景。

内容的提问来源于stack exchange,提问作者Federico elbambolo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 04:04:55