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

Livewire组件表单提交后动态生成的下拉菜单消失(Alpine.js v2.8环境)

Livewire组件表单提交后动态生成的下拉菜单消失(Alpine.js v2.8环境)

我正在开发一个带多选下拉菜单的Laravel Livewire组件,下拉选项是用JavaScript动态生成的,但提交表单后,下拉选项就消失了。

下面是下拉菜单的核心HTML代码:

<div id="dropdown" style="display: none;"
    class="absolute z-10 mt-1 w-full bg-white shadow-lg max-h-60 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm"
    wire:ignore.self>
    <!-- Dynamically generated options will go here -->
</div>

问题的核心限制是:我没法配合@livewireScripts使用最新版的Alpine.js,因为我依赖的一个库已经内置了Alpine v2.8,而且这个库的代码是混写在一起的,没办法单独提取出需要的Alpine代码。

表单提交前一切功能正常,但一旦提交表单、Livewire组件完成刷新,下拉菜单就会消失。

完整的前端代码如下:

HTML部分

<div class="relative">
    <label class="block text-sm mb-1" for="roles">Mention roles</label>
    <div class="mt-1 relative">
        <button type="button" id="toggleDropdown"
            class="relative w-full bg-white border border-gray-200 rounded-md shadow-sm pl-3 pr-10 py-2 text-left cursor-default focus:outline-none focus:ring-1 focus:ring-primary focus:border-primary sm:text-sm">
            <span id="displayText" class="block truncate">Select roles</span>
            <span class="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
                <svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg"
                    viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
                    <path fill-rule="evenodd"
                        d="M10 3a1 1 0 01.707.293l3 3a1 1 0 01-1.414 1.414L10 5.414 7.707 7.707a1 1 0 01-1.414-1.414l3-3A1 1 0 0110 3zm-3.707 9.293a1 1 0 011.414 0L10 14.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z"
                        clip-rule="evenodd" />
                </svg>
            </span>
        </button>

        <div id="dropdown" style="display: none;"
            class="absolute z-10 mt-1 w-full bg-white shadow-lg max-h-60 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm"
            wire:ignore.self>
            <!-- Dynamically generated options will go here -->
        </div>
    </div>
</div>

<input type="hidden" id="selectedRoles" wire:model="selectedRoles">

JavaScript部分

let isDropdownInitialized = false; // Flag to track if dropdown is initialized

function initializeDropdown(roles) {
    console.log('Initializing dropdown with roles:', roles); // Debug: Check roles passed to the function

    const selectedRolesInput = document.getElementById('selectedRoles');
    const toggleDropdownButton = document.getElementById('toggleDropdown');
    const dropdown = document.getElementById('dropdown');
    const displayText = document.getElementById('displayText');
    const dropdownContainer = document.querySelector('.relative');

    let selectedOptions = [];

    // Function to create dropdown items
    function createDropdownItems() {
        console.log('Creating dropdown items'); // Debug: Track when dropdown items are created
        dropdown.innerHTML = ''; // Clear previous dropdown items

        roles.forEach(role => {
            console.log('Creating item for role:', role); // Debug: Track each role being added

            const div = document.createElement('div');
            div.classList.add('cursor-pointer', 'select-none', 'relative', 'py-2', 'pl-3', 'pr-9',
                'hover:bg-primary', 'hover:text-white');
            div.setAttribute('data-role-id', role.id);
            div.addEventListener('click', function(event) {
                console.log('Role clicked:', role); // Debug: Track role selection
                event.stopPropagation();
                toggleOption(role);
            });

            const span = document.createElement('span');
            span.textContent = role.name;
            span.classList.add('block', 'truncate');

            const checkIcon = document.createElement('span');
            checkIcon.classList.add('absolute', 'inset-y-0', 'right-0', 'flex', 'items-center', 'pr-4',
                'text-primary');
            checkIcon.style.display = selectedOptions.some(selected => selected.id === role.id) ? 'block' :
                'none';

            const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            svg.setAttribute('class', 'h-5 w-5');
            svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
            svg.setAttribute('viewBox', '0 0 20 20');
            svg.setAttribute('fill', 'currentColor');

            const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
            path.setAttribute('fill-rule', 'evenodd');
            path.setAttribute('d',
                'M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z'
                );
            path.setAttribute('clip-rule', 'evenodd');

            svg.appendChild(path);
            checkIcon.appendChild(svg);
            div.appendChild(span);
            div.appendChild(checkIcon);
            dropdown.appendChild(div);
        });
    }

    // Toggle the dropdown visibility
    toggleDropdownButton.addEventListener('click', function(event) {
        console.log('Dropdown toggle clicked'); // Debug: Track toggle button click
        event.stopPropagation();
        dropdown.style.display = dropdown.style.display === 'none' ? 'block' : 'none';
    });

    // Toggle selection of a role
    function toggleOption(role) {
        console.log('Toggling selection for role:', role); // Debug: Track role selection toggle
        const index = selectedOptions.findIndex(selected => selected.id === role.id);
        if (index !== -1) {
            selectedOptions.splice(index, 1);
        } else {
            selectedOptions.push(role);
        }
        updateDisplayText();
        createDropdownItems();
        updateSelectedRolesInput();
    }

    // Update the displayed text of selected roles
    function updateDisplayText() {
        console.log('Updating display text with selected options:',
        selectedOptions); // Debug: Track selected options
        displayText.textContent = selectedOptions.length ? selectedOptions.map(option => option.name)
            .join(', ') : 'Select roles';
    }

    // Update the hidden input field with selected roles
    function updateSelectedRolesInput() {
        const selectedIds = selectedOptions.map(option => option.id).join(',');
        selectedRolesInput.value = selectedIds;
        selectedRolesInput.dispatchEvent(new Event('input'));
        console.log('Updated selected roles input:', selectedIds); // Debug: Track updated input value
    }

    // Initialize the dropdown items
    createDropdownItems();

    // Close the dropdown if clicked outside
    document.addEventListener('click', function(event) {
        if (!dropdownContainer.contains(event.target) && dropdown.style.display === 'block') {
            console.log('Closing dropdown (clicked outside)'); // Debug: Track dropdown close action
            dropdown.style.display = 'none';
        }
    });
}

document.addEventListener('livewire:initialized', () => {
    @this.on('send-message', (data) => {
        // 原代码此处console内容不完整,保留现有结构
    });
});

备注:内容来源于stack exchange,提问作者Tillie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 13:13:04