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
相关产品推荐
相关产品推荐

