Как опознать блоки со спойлерами, а также заголовки и контент у них внутри; какой класс надо переключать; как контент должен изменять свою видимость. Ну и сама логика переключения видимости контента - при закрытии спойлеров не надо обрабатывать текущий, т.е., инвертировали состояние кликнутого, взяли все, отбросили кликнутый, закрыли:
const containerSelector = '.spoiler-container';
const headerSelector = '.spoiler-header';
const contentSelector = '.spoiler-content';
const activeClass = 'active';
const toggleEffect = 'slideToggle'; // или fadeToggle, или toggle
const hideEffect = 'slideUp'; // или fadeOut, или hide
function toggle($containers, $container) {
$containers
.not($container)
.removeClass(activeClass)
.find(contentSelector)
[hideEffect]();
$container
.toggleClass(activeClass)
.find(contentSelector)
[toggleEffect]();
}
Обработчик клика подключается блокам со спойлерами, но клики слушаться будут только по заголовкам:
const $containers = $(containerSelector).on('click', headerSelector, e => {
toggle($containers, $(e.delegateTarget));
});
В случае, если предполагается добавление новых блоков уже после подключения обработчика, то его, обработчик, следует добавить на документ - так всё будет работать как надо без каких-либо дополнительных телодвижений:
$(document).on('click', `${containerSelector} ${headerSelector}`, e => {
toggle($(containerSelector), $(e.target).closest(containerSelector));
});