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

Angular5环境下NVDA仅朗读最后加载的div内容问题咨询

问题根因

你遇到的NVDA仅播报最后一个动态内容的问题,是两个核心原因导致的:

  • 短时间内多个aria-live区域同时触发更新,NVDA的默认策略会合并同批次的live区域播报内容,仅输出最后一条。语音查看器能看到所有内容是因为记录了所有更新事件,但语音播报时做了合并处理。
  • 属性配置冲突:role="alert"本身隐含aria-live="assertive"、aria-atomic="true"属性,你同时配置aria-live="polite"属于冗余冲突,同时每个动态内容都单独加live属性,导致多个并行的live区域同时触发更新。
修复方案

1. 清理冗余无障碍属性

移除所有内部p、div上重复的role="alert"、aria-live、aria-atomic属性,仅在最外层的动态内容包裹层配置一次live属性即可,修改后HTML模板如下:

<input type="button" value="Click Me" tabindex="0" (click)="getWatsonDetails()"/>
<!-- 仅在外层配置一次aria-live -->
<div *ngIf="isHiddenData" aria-live="polite" aria-atomic="true">
  <div id="main{{i}}" tabindex="-1" class="chat" *ngFor="let passage of watsonResponse;let i=index;">
    <p tabindex="0" style="font-size: medium; margin-bottom: 4px;">
      {{passage.value.input.text}}
    </p>
    <div tabindex="-1" style="margin-bottom:4px;" *ngIf="passage.who==='watson'&& passage.label==='DL codes'">
      <span class="btn-group-star" *ngFor="let item of passage.value.codesWithLinks; let pwe=index">
        <button class="btn btn-secondary wlDlBtn" tabindex="0" id="pdfbtn{{i}}{{pwe}}" *ngIf="item.type==='pdf'" type="button"
                placement="top-left" attr.aria-label="{{'Document '+item.code}}">
          <span>{{'Document - '+item.code}}</span>
        </button>

        <button class="btn btn-secondary wlDlBtn" tabindex="0" id="wblbtn{{i}}{{pwe}}" *ngIf="item.type==='weblink'" type="button"
                placement="top-left" attr.aria-label="{{'Document '+item.code}} ">
          <span role="link">{{'Web Link - '+item.code}}</span>
        </button>

        <button class="btn btn-secondary wlDlBtn" tabindex="0" id="excelbtn{{i}}{{pwe}}" *ngIf="item.type==='excel'" type="button"
                placement="top-left" attr.aria-label="{{'Document '+item.code}} ">
          <span>{{'Document - '+item.code}}</span>
        </button>
        <br>
      </span>
    </div>
    <div tabindex="-1" style="font-size: medium; margin-bottom: 4px;" *ngIf="passage.who==='watson' && passage.label==='Relevance node'">
      <p tabindex="0"> {{passage.value.input.text}} </p> <br />
      <div style="display:flex;margin-top: 1em;">
        <div id="drop_{{i}}">
          <button role="checkbox" tabindex="0" id="feedbackDropBtn_{{i}}" aria-expanded="false" aria-label="select" class="drop-toggle btn flat">
            <span aria-hidden="true">Select</span>
            <span id="feedbackDropBtn" aria-hidden="true">Select</span>
            <i class="fa fa-angle-down"></i>
          </button>
          <div id="feedback_{{i}}" class="drop-show" *ngIf="!passage.isDisabled" style="height: 85px;margin-left: 3%;overflow-y: scroll;">
            <label id="check{{cb}}" *ngFor="let option of optionsArray;let cb=index">
              <input type="checkbox" id="checkItem_{{i}}{{cb}}" attr.aria-labelledby="{{'chkbx' + cb}}" name="checkbox" tabindex="0" />
              <span id="chkbx{{cb}}">{{option.code}}</span>
            </label>
          </div>
        </div>
        <span>
          <button type="button" tabindex="0" aria-label="Submit" style="text-align: center;height: 2.2em;margin-left: 0.5em;" class="submitbtn" id="submit_{{i}}">
            <span style="color:#4E8416">Submit</span>
          </button>
        </span>
      </div>
    </div>
  </div>
</div>

2. 调整内容渲染逻辑避免同时更新

如果需要分段播报所有内容,不要一次性渲染全部内容,改成间隔逐个加载,避免NVDA合并播报,修改后的TS代码如下:

// 原始全量数据单独存储
fullWatsonData: any = [{ "label": "text", "value": { "input": { "text": "Here are the documents or links that I found that match most closely to your search criteria. Click on a link to view the document in the Document Viewer. If the link is for a webpage, the link will be opened in a new tab in your browser." } }, "who": "watson", "time": "2021-9-3|9:39:29" }, { "label": "DL codes", "value": { "input": { "text": "AB0003,AB0037" }, "codesWithLinks": [{ "code": "AB0003", "link": "", "summary": "Cultural Competency Training 2021", "type": "pdf", "DLWL_links_int": "", "checked": false }, { "code": "AB0037", "link": "", "summary": "Cultural Competency Training 2020", "type": "pdf", "DLWL_links_int": "", "checked": false }, { "code": "None", "checked": false }] }, "who": "watson", "time": "2021-9-3|9:39:29" }, { "label": "Relevance node", "value": { "input": { "text": "Were you able to find what you were looking for?  Please help us continue to improve your experience by selecting the document in the drop-down menu that best helped you and clicking submit for a thumbs-up.  If you did not find what you were looking for, please select “None” from the drop-down and click submit for a thumbs-down to continue." } }, "who": "watson", "time": "2021-9-3|9:39:29" }]
// 渲染用数组默认空
watsonResponse: any = []
optionsArray: any = [{ "code": "Dot net" }, { "code": "Java" }, { "code": "Python" }];
isHiddenData: boolean = false;

async getWatsonDetails() {
  this.isHiddenData = true;
  this.watsonResponse = [];
  // 逐个加载内容,间隔150ms,错开更新时间
  for(let item of this.fullWatsonData) {
    this.watsonResponse.push(item);
    await new Promise(resolve => setTimeout(resolve, 150));
  }
}

3. 可选优化

如果不需要打断用户当前操作,不要使用role="alert",该属性属于断言型播报,会强制中断用户当前正在听的内容,普通动态内容用aria-live="polite"即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 19:36:02