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

含分号/冒号的data-target导致aria-expanded按钮无法展开问题

解决Bootstrap折叠组件中ID含特殊字符无法触发展开的问题

核心问题分析

  1. aria-controls属性错误:你当前代码里给aria-controls加了#前缀,这个属性不需要#,它是直接关联目标元素的ID,不是CSS选择器。
  2. data-target选择器未转义:Bootstrap的data-target使用CSS选择器语法,而:、;属于CSS特殊字符,直接使用会导致选择器解析失败,无法匹配目标元素。

解决方案

1. 修正aria-controls属性

直接去掉aria-controls里的#,只保留目标ID:

aria-controls="vsn-{{vs_feat_name[1:]}}-end"

2. 给data-target的选择器转义特殊字符

在Jinja2中添加自定义过滤器来转义CSS特殊字符,这样既能保留原始字符的业务含义,又能让选择器生效:

# 在Flask应用中注册自定义过滤器
@app.template_filter('escape_css')
def escape_css_selector(value):
    # 转义CSS选择器中的特殊字符,HTML属性中需要双反斜杠
    return value.replace(':', '\\:').replace(';', '\\;')

然后在模板中使用这个过滤器处理data-target:

data-target="#vsn-{{vs_feat_name[1:]|escape_css}}-end"

3. 保留原始ID

目标折叠容器的ID不需要修改,直接保留包含特殊字符的原始值即可(HTML规范允许ID包含:、;这类字符):

<div class="collapse" id="vsn-{{vs_feat_name[1:]}}-end">
  <!-- 折叠内容 -->
</div>

4. 手动初始化折叠(可选,解决极端兼容问题)

如果上述调整后仍有问题,可以手动用JS初始化折叠逻辑,绕过Bootstrap内置选择器的解析问题:

// 等待DOM加载完成
document.addEventListener('DOMContentLoaded', function() {
  document.querySelectorAll('[data-toggle="collapse"]').forEach(btn => {
    // 获取目标ID(从aria-controls直接取,避免选择器解析问题)
    const targetId = btn.getAttribute('aria-controls');
    const target = document.getElementById(targetId);
    if (!target) return;

    // 绑定点击事件
    btn.addEventListener('click', function() {
      // 切换折叠状态
      target.classList.toggle('show');
      // 更新aria-expanded属性
      btn.setAttribute('aria-expanded', target.classList.contains('show'));
    });
  });
});

修正后的完整代码示例

<button tabindex='0' role="button" type="button" class="btn btn-outline-dark m-1" 
        data-toggle="collapse" 
        data-target="#vsn-{{vs_feat_name[1:]|escape_css}}-end" 
        aria-expanded="false" 
        aria-controls="vsn-{{vs_feat_name[1:]}}-end">
  <span style="font-weight:bold; text-transform:uppercase;">{{ vs_feat_name+' ('+vs_val['count']|string+')' }}</span>
</button>
<div class="collapse" id="vsn-{{vs_feat_name[1:]}}-end">
  <div class="card border border-dark" style="max-height: 500px; overflow-y: scroll; padding: 1rem">
    <div class="card-header">
      <p>
        Frames containing <span style="text-transform: uppercase;">{{vs_feat_name}}: </span>{{ vs_val['vn_class_mem']|length }}<br>
      </p>
    </div>
    <div class="card card-body">
      <h5>
        {% for vn_mem in vs_val['vn_class_mem'] %}
        <button tabindex='0' role="button" type="button" class="btn btn-outline-dark m-1" data-toggle="button" onclick="window.location.href='{{ url_for( 'render_vn_class', vn_class_id=vn_mem) }}';">
          <span style="font-weight:bold; text-transform:uppercase;">{{ vn_mem }}</span>
        </button>
        {% endfor %}
      </h5>
    </div>
  </div>
</div>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 16:23:14