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

JQuery AJAX级联回调函数失效问题求助

问题分析与修复方案

我有三个关联的select组件,层级为 UnitType >> UnitSubType >> Unit,为减少冗余写了可复用的fetchItems函数填充数据。首次调用正常,但后续级联操作没触发,无报错,控制台打印了回调日志(---- Callback -----、Callback: fetchItems Next Type: UnitSubType)但实际没执行回调。

原函数代码

function fetchItems(type) {
    let apiurl 
    let avail = '#available';
    let callback = '';
    let filter = '';
    let filterValues = '';
    let listID = '#hfSelected';
    let json = '#json';
    let nextType = '';
    let select = '#selected';

    switch (type) {
        case 'UnitType':
            apiurl = baseUnitTypesAPI + 0;
            avail += 'UnitTypes';
            callback = 'fetchItems';
            listID += 'UnitTypes';
            json += 'UnitTypes';
            nextType = 'UnitSubType';
            select += 'UnitTypes';

            break;
        case 'UnitSubType':
            apiurl = baseUnitSubTypesAPI + 0;
            avail += 'UnitSubTypes';
            callback = 'fetchItems';
            filterValues = $('#hfSelectedUnitTypes').val();
            listID += 'UnitSubTypes';
            json += 'UnitSubTypes';
            //nextType = 'Unit';
            select += 'UnitSubTypes';

            filter = "{ UnitTypes: '" + filterValues + "'}";
        case 'Unit':
            apiurl = baseUnitsAPI + 0;
            avail += 'Units';
            filterValues = $('#hfSelectedUnitSubTypes').val();
            listID += 'Units';
            json += 'Units';
            select += 'Units';

            filter = "{ UnitSubTypes: '" + filterValues + "'}";
        default:
            return;
    }

    //console.log('Type: ' + type);
    //console.log('API: ' + apiurl);
    //console.log('Available: ' + avail);
    //console.log('Callback: ' + callback);
    //console.log('Filter: ' + filter);
    //console.log('FilterValues: ' + filterValues);
    //console.log('ListID: ' + listID);
    //console.log('JSON: ' + json);
    //console.log('Next Type:' + nextType);
    //console.log('Select: ' + select);
    //console.log('-----------------------------------------------');

    $.ajax({
        url: apiurl,
        contentType: 'application/json; charset=utf-8',
        dataType: "json",
        data: (filterValues.length > 0) ? filter : '',
        type: (filterValues.length > 0) ? 'POST' : 'GET',
        beforeSend: function () {
            $(avail).empty();
            $(select).empty();
        },
        success: function (data) {
            let selectedItems = $(listID).val().split(",");
            let newSelectedItems = [];

            $(json).val(data);

            $.each(JSON.parse(data), function (i, item) {
                if (selectedItems.includes(item.ID.toString())) {
                    $(select).append(baseItem.replace('#ItemID', item.ID).replace('#ItemName', item.Name).replace('#ItemType', type));
                    newSelectedItems.push(item.ID)
                } else {
                    $(avail).append($('<option>', {
                        value: item.ID,
                        text: item.Name
                    }));
                }
                
            });

            $(listID).val(newSelectedItems.join(','));
            if (callback != '' && nextType != '') {
                console.log('---- Callback -----');
                console.log('Callback: ' + callback + ' Next Type: ' + nextType)
                window[callback](nextType)
            }
        }
    });
}

核心问题原因

  • switch分支缺失break:case 'UnitSubType'和case 'Unit'末尾未添加break,导致执行完当前分支后会继续向下执行后续分支代码,最终走到default分支直接return,ajax请求根本没机会执行。
  • 手动拼接JSON格式filter存在风险:若filterValues包含特殊字符(如引号),会导致JSON格式错误。
  • 回调用字符串引用不够严谨:字符串引用依赖全局作用域,直接使用函数引用更可靠。

修复后的代码

function fetchItems(type) {
    let apiurl;
    let avail = '#available';
    let callback = fetchItems;
    let filter = {};
    let filterValues = '';
    let listID = '#hfSelected';
    let json = '#json';
    let nextType = '';
    let select = '#selected';

    switch (type) {
        case 'UnitType':
            apiurl = baseUnitTypesAPI + 0;
            avail += 'UnitTypes';
            listID += 'UnitTypes';
            json += 'UnitTypes';
            nextType = 'UnitSubType';
            select += 'UnitTypes';
            break;
        case 'UnitSubType':
            apiurl = baseUnitSubTypesAPI + 0;
            avail += 'UnitSubTypes';
            filterValues = $('#hfSelectedUnitTypes').val();
            listID += 'UnitSubTypes';
            json += 'UnitSubTypes';
            //nextType = 'Unit';
            select += 'UnitSubTypes';
            if (filterValues) {
                filter.UnitTypes = filterValues;
            }
            break;
        case 'Unit':
            apiurl = baseUnitsAPI + 0;
            avail += 'Units';
            filterValues = $('#hfSelectedUnitSubTypes').val();
            listID += 'Units';
            json += 'Units';
            select += 'Units';
            if (filterValues) {
                filter.UnitSubTypes = filterValues;
            }
            callback = null;
            break;
        default:
            return;
    }

    $.ajax({
        url: apiurl,
        contentType: 'application/json; charset=utf-8',
        dataType: "json",
        data: Object.keys(filter).length > 0 ? JSON.stringify(filter) : '',
        type: Object.keys(filter).length > 0 ? 'POST' : 'GET',
        beforeSend: function () {
            $(avail).empty();
            $(select).empty();
        },
        success: function (data) {
            let selectedItems = $(listID).val()?.split(",") || [];
            let newSelectedItems = [];

            $(json).val(data);

            $.each(JSON.parse(data), function (i, item) {
                const itemIdStr = item.ID.toString();
                if (selectedItems.includes(itemIdStr)) {
                    $(select).append(baseItem.replace('#ItemID', item.ID).replace('#ItemName', item.Name).replace('#ItemType', type));
                    newSelectedItems.push(itemIdStr);
                } else {
                    $(avail).append($('<option>', {
                        value: item.ID,
                        text: item.Name
                    }));
                }
            });

            $(listID).val(newSelectedItems.join(','));
            if (callback && nextType) {
                console.log('---- Callback -----');
                console.log('Callback: fetchItems Next Type: ' + nextType);
                callback(nextType);
            }
        }
    });
}

修复点说明

  1. 给case 'UnitSubType'和case 'Unit'添加break语句,确保每个分支执行完后跳出switch,避免提前return。
  2. 将filter改为对象存储,用JSON.stringify转换为合法JSON字符串,避免特殊字符导致的格式错误。
  3. 回调直接使用函数引用fetchItems代替字符串,调用时直接执行callback(nextType),比window[callback]更可靠。
  4. 处理selectedItems为空的情况,避免split空值导致的异常。
  5. Unit作为最后一级,设置callback = null,避免不必要的回调触发。

内容的提问来源于stack exchange,提问作者P S

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.07 05:14:51