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

Tom Select:选中父选项时禁用子选项的实现难题

Tom Select多选组件父选项选中后子选项无法禁用的问题

问题背景

使用Tom Select的多选下拉组件搭配checkbox_options插件实现文件夹结构选择功能,选项按父文件夹分组。需求是选中顶级文件夹(如app)时,自动禁用其子选项(如app/Helpers、app/Http),阻止用户选择。

当前配置

  • 使用checkbox_options插件
  • select字段包含optgroup元素,选项通过data-groups属性标记父分组

HTML结构

<select id="myFolders" name="folders[]" multiple autocomplete="off">
    <optgroup label="app">
        <option value="app" selected>app</option>
        <option value="app/Helpers">app/Helpers</option>
        <option value="app/Http">app/Http</option>
    </optgroup>
</select>

尝试的JavaScript代码

const tomSelect = new TomSelect('#myFolders', {
    plugins: {
        'checkbox_options': {
            'checkedClassNames':   ['ts-checked'],
            'uncheckedClassNames': ['ts-unchecked'],
            'className': 'form-check-input'
        },
        'remove_button': {
            title:'Remove this item',
        }
    },
    onChange: function () {
        updateDisabledOptions(this);
    }
});

function updateDisabledOptions(tomSelectInstance) {
    const selectedValues = tomSelectInstance.getValue();
    const selectedGroups = new Set(selectedValues);

    Object.values(tomSelectInstance.options).forEach(option => {
        const optionElement = document.querySelector(`.ts-dropdown [data-value="${option.value}"]`);
        
        if (optionElement) {
            const checkbox = optionElement.querySelector('.form-check-input');

            if (checkbox) {
                const isChildOfSelectedGroup = Array.from(selectedGroups).some(
                    group => option.value.startsWith(group + '/')
                );

                if (isChildOfSelectedGroup) {
                    optionElement.classList.add('disabled');
                    checkbox.setAttribute('disabled', true);
                } else {
                    optionElement.classList.remove('disabled');
                    checkbox.removeAttribute('disabled');
                }
            }
        }
    });
}

遇到的问题

上述代码已为子复选框添加disabled属性,但仍无法阻止选中,即使设置aria-disabled属性,复选框仍可被选择。

疑问

  1. 能否在Tom Select中实现父选项选中时子复选框不可选?
  2. 是否遗漏了Tom Select的特定处理逻辑?

解决方案

问题根源

直接修改DOM元素的disabled属性无效,因为Tom Select会自主管理选项的选中状态,插件的事件监听优先级高于原生属性限制。必须通过Tom Select内部API修改选项状态,同时拦截用户交互事件。

修改后的代码

const tomSelect = new TomSelect('#myFolders', {
    plugins: {
        'checkbox_options': {
            'checkedClassNames':   ['ts-checked'],
            'uncheckedClassNames': ['ts-unchecked'],
            'className': 'form-check-input'
        },
        'remove_button': {
            title:'Remove this item',
        }
    },
    onChange: function () {
        updateDisabledOptions(this);
    },
    // 初始化时执行禁用逻辑,适配默认选中的父选项
    onInitialize: function() {
        updateDisabledOptions(this);
    }
});

function updateDisabledOptions(tomSelectInstance) {
    const selectedValues = tomSelectInstance.getValue();
    const selectedGroups = new Set(selectedValues);

    Object.values(tomSelectInstance.options).forEach(option => {
        const optionElement = document.querySelector(`.ts-dropdown [data-value="${option.value}"]`);
        
        if (optionElement) {
            const checkbox = optionElement.querySelector('.form-check-input');
            const isChildOfSelectedGroup = Array.from(selectedGroups).some(
                group => option.value.startsWith(group + '/')
            );

            if (isChildOfSelectedGroup) {
                // 标记Tom Select内部选项为禁用
                option.disabled = true;
                // 更新DOM样式与属性
                optionElement.classList.add('disabled');
                checkbox.setAttribute('disabled', true);
                // 拦截点击事件,彻底阻止交互
                optionElement.style.pointerEvents = 'none';
                // 移除已选中的子选项,保证逻辑一致
                if (selectedValues.includes(option.value)) {
                    tomSelectInstance.removeItem(option.value);
                }
            } else {
                // 恢复选项启用状态
                option.disabled = false;
                optionElement.classList.remove('disabled');
                checkbox.removeAttribute('disabled');
                optionElement.style.pointerEvents = 'auto';
            }
        }
    });

    // 强制刷新组件,同步内部状态到DOM
    tomSelectInstance.refreshOptions();
}

关键修改说明

  1. 修改内部选项状态:直接设置option.disabled = true,让Tom Select核心逻辑识别该选项为禁用状态,而非仅修改DOM。
  2. 拦截交互事件:通过pointerEvents: none禁用选项元素的所有点击事件,彻底阻止用户触发选中操作。
  3. 同步选中状态:如果父选项选中时子选项已被选中,自动移除子选项,避免出现父与子同时选中的矛盾状态。
  4. 初始化执行逻辑:添加onInitialize钩子,页面加载时就根据默认选中的父选项处理子选项禁用。
  5. 强制刷新组件:调用refreshOptions()确保Tom Select将内部状态同步到DOM界面。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 19:04:51