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

Angular中ngFor结合mat-accordion实现多分类搜索功能时遍历异常问题求助

问题分析与解决方案

这个问题我之前也碰到过,核心原因是你循环生成的多个过滤器面板用了重复的id属性(searchInput和searchUL)。在HTML规范里id是全局唯一标识,document.getElementById()只会返回页面中第一个匹配该id的元素,所以不管你在哪个面板的搜索框输入内容,实际操作的都是第一个面板的列表,自然其他面板的搜索功能失效了。

下面给你两种解决方案,优先推荐Angular数据驱动的实现方式,更符合框架设计理念:


方案一:使用Angular数据绑定+过滤逻辑(推荐)

完全避免直接操作DOM,通过绑定搜索词到每个分类项,再用数据过滤实现搜索功能,更稳定也更易维护。

1. 修改HTML模板

<div *ngFor="let item of categoryFilters?.filter; let i = index">
  <div class="FilterDirectory-titleBar" >
    <!-- 绑定当前分类项的搜索词,去掉重复id -->
    <input type="text" [(ngModel)]="item.searchTerm" class="FilterDirectory-searchInput" placeholder="搜索..." />
    <span class="close-search" (click)="item.showSearch = false" >
      <i class="fa fa-times" aria-hidden="true"></i >
    </span>
  </div>
  <div class="card product-list-header" style="border: none" >
    <span class="open-search" (click)="item.showSearch = true">
      <i class="fa fa-search"></i>
    </span>
    <mat-accordion class="filter-product-expansion">
      <mat-expansion-panel [expanded]="true">
        <mat-expansion-panel-header style="background-color: #fff" >
          <h5 class="float-left" > {{ item.title }} </h5>
        </mat-expansion-panel-header>
        <span class="clearfix"></span>
        <ul>
          <!-- 调用过滤方法,仅显示匹配搜索词的项 -->
          <div *ngFor="let items of getFilteredItems(item); let i = index">
            <li *ngIf="items.active">
              <a class="search-title">{{ items.title }}</a>
              <div class="card-body" >
                <div class="form-group">
                  <div class="row">
                    <div class="col-md-10 filter-col" style="padding: 0" >
                      <label class="radio-inline">
                        <p-checkbox name="item.title" value="{{ items?.uuid }}" label="{{ items?.title }}" >
                        </p-checkbox>
                      </label>
                    </div>
                    <div class="product-count">
                      <p> ({{ items.productCount ? items.productCount : "" }}) </p>
                    </div>
                  </div>
                </div>
              </div>
            </li>
          </div>
        </ul>
      </mat-expansion-panel>
    </mat-accordion>
  </div>
</div>

2. 修改TS代码

首先初始化每个分类项的搜索词,再添加过滤方法:

// 在获取categoryFilters数据后(比如ngOnInit或数据订阅回调中),初始化搜索词
ngOnInit() {
  // 假设你已经获取到categoryFilters数据
  this.categoryFilters.filter.forEach(item => {
    item.searchTerm = ''; // 初始化搜索词为空
  });
}

// 根据当前分类项的搜索词过滤列表
getFilteredItems(item: any): any[] {
  // 搜索词为空时返回全部数据
  if (!item.searchTerm.trim()) {
    return item.value;
  }
  const filterTerm = item.searchTerm.toUpperCase();
  // 过滤出标题包含搜索词的项
  return item.value.filter(items => 
    items.title.toUpperCase().includes(filterTerm)
  );
}

方案二:修改DOM元素ID为唯一值(兼容原有逻辑)

如果你想保留原有DOM操作的逻辑,只需要给每个面板的搜索框和列表设置唯一ID,再传递索引区分:

1. 修改HTML模板

<div *ngFor="let item of categoryFilters?.filter; let i = index">
  <div class="FilterDirectory-titleBar" >
    <!-- 设置唯一ID:searchInput-索引值 -->
    <input type="text" id="searchInput-{{i}}" (input)="searchCategory(i)" class="FilterDirectory-searchInput" />
    <span class="close-search" (click)="item.showSearch = false" >
      <i class="fa fa-times" aria-hidden="true"></i >
    </span>
  </div>
  <div class="card product-list-header" style="border: none" >
    <span class="open-search" (click)="item.showSearch = true">
      <i class="fa fa-search"></i>
    </span>
    <mat-accordion class="filter-product-expansion">
      <mat-expansion-panel [expanded]="true">
        <mat-expansion-panel-header style="background-color: #fff" >
          <h5 class="float-left" > {{ item.title }} </h5>
        </mat-expansion-panel-header>
        <span class="clearfix"></span>
        <!-- 设置唯一ID:searchUL-索引值 -->
        <ul id="searchUL-{{i}}">
          <div *ngFor="let items of item.value; let i = index">
            <li *ngIf="items.active">
              <a class="search-title">{{ items.title }}</a>
              <div class="card-body" >
                <div class="form-group">
                  <div class="row">
                    <div class="col-md-10 filter-col" style="padding: 0" >
                      <label class="radio-inline">
                        <p-checkbox name="item.title" value="{{ items?.uuid }}" label="{{ items?.title }}" >
                        </p-checkbox>
                      </label>
                    </div>
                    <div class="product-count">
                      <p> ({{ items.productCount ? items.productCount : "" }}) </p>
                    </div>
                  </div>
                </div>
              </div>
            </li>
          </div>
        </ul>
      </mat-expansion-panel>
    </mat-accordion>
  </div>
</div>

2. 修改TS的searchCategory方法

searchCategory(index: number) {
  var input, filter, ul, li, a, i, txtValue;
  // 根据索引获取当前面板的搜索框和列表
  input = document.getElementById(`searchInput-${index}`);
  filter = input.value.toUpperCase();
  ul = document.getElementById(`searchUL-${index}`);
  li = ul.getElementsByTagName('li');
  
  for (i = 0; i < li.length; i++) {
    a = li[i].getElementsByTagName('a')[0];
    txtValue = a.textContent || a.innerText;
    if (txtValue.toUpperCase().indexOf(filter) > -1) {
      li[i].style.display = '';
    } else {
      li[i].style.display = 'none';
    }
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 15:03:12