如何阻止ion-change在存储值加载完成前触发?
你的问题根源在于:每个toggle的Loaded变量是独立异步设置的,当最后一个toggle的documentRejectedLoaded被设为true时,allAlertsLoaded()会立刻返回true,但此时这个toggle的ngModel刚从初始值false更新为存储的真实值,触发了ionChange事件。而你的toggle函数会读取当前存储的值并反转它,这就导致最后一个toggle的状态被错误地切换回去了。
这里有几个更可靠的修复方案:
方案1:用Promise.all统一加载所有配置,避免分步触发ionChange
把多个异步的storage.get请求合并成一个,等所有值都读取完成后再一次性更新所有ngModel,同时设置一个全局的加载完成标志。这样所有toggle的初始值只会更新一次,且不会在加载过程中触发ionChange(因为加载完成前标志为false,会忽略事件)。
修改组件代码:
- 替换多个
Loaded变量为一个全局标志:
isAllAlertsLoaded = false;
- 重写
loadToggles函数,用Promise.all并行读取所有存储值:
loadToggles() { // 并行读取所有配置项,避免串行等待 Promise.all([ this.storage.get(NOTIFICATIONS_ENABLED), this.storage.get(JOB_RECEIVED), this.storage.get(DOCUMENT_CREATED), this.storage.get(DOCUMENT_REJECTED) ]).then(([notificationsVal, jobVal, docCreatedVal, docRejectedVal]) => { // 一次性更新所有ngModel,避免分步触发ionChange事件 this.notificationsEnabled = notificationsVal ?? false; // 加默认值处理null/undefined情况 this.jobReceived = jobVal ?? false; this.documentCreated = docCreatedVal ?? false; this.documentRejected = docRejectedVal ?? false; // 所有值加载完成后,设置全局标志为true this.isAllAlertsLoaded = true; }); }
- 优化
toggle函数,直接用当前toggle的ngModel值更新存储,避免重复读取:
toggle(alertConst: string, currentValue: boolean) { if (!this.isAllAlertsLoaded) { return; } // 直接用当前选中状态更新存储,不用再读取后反转,逻辑更清晰 this.storage.set(alertConst, currentValue); }
修改模板代码:
在ionChange事件中传递当前toggle的ngModel值:
<table> <tr> <td valign="middle" class="alertTitle"><p>Enable Notifications</p></td> <td><ion-toggle [(ngModel)]="notificationsEnabled" (ionChange)="toggle('NOTIFICATIONS_ENABLED', notificationsEnabled)"></ion-toggle></td> </tr> <tr> <td valign="middle" class="alertTitle"><p>Job Received</p></td> <td><ion-toggle [(ngModel)]="jobReceived" (ionChange)="toggle('JOB_RECEIVED', jobReceived)"></ion-toggle></td> </tr> <tr> <td valign="middle" class="alertTitle"><p>Document Created</p></td> <td><ion-toggle [(ngModel)]="documentCreated" (ionChange)="toggle('DOCUMENT_CREATED', documentCreated)"></ion-toggle></td> </tr> <tr> <td valign="middle" class="alertTitle"><p>Document Rejected</p></td> <td><ion-toggle [(ngModel)]="documentRejected" (ionChange)="toggle('DOCUMENT_REJECTED', documentRejected)"></ion-toggle></td> </tr> </table>
方案2:加载完成前隐藏/禁用toggle(可选)
如果不想处理事件触发问题,可以在加载完成前用disabled属性禁用toggle,或者用*ngIf隐藏:
<ion-toggle [(ngModel)]="notificationsEnabled" (ionChange)="toggle('NOTIFICATIONS_ENABLED', notificationsEnabled)" [disabled]="!isAllAlertsLoaded" ></ion-toggle>
这样用户在加载过程中无法操作,也不会有意外的事件触发。
为什么你的原有方案会失败?
当最后一个toggle的documentRejectedLoaded被设为true时,allAlertsLoaded()立刻返回true,但此时这个toggle的ngModel刚从false更新为存储的真实值,触发了ionChange。你的toggle函数会读取存储中的旧值(此时还没被更新),然后反转它,导致存储的值被错误地改成了相反状态,最终toggle显示为关闭。
内容的提问来源于stack exchange,提问作者Lewis Smith

