Ionic双用户菜单切换异常:登出换账号后菜单未更新
解决Ionic切换用户后菜单不更新的问题
看起来你遇到的核心问题是:切换用户账号后,菜单没有根据新用户类型重新加载。这是因为你的菜单初始化逻辑只在App组件的initializeApp方法里执行了一次——这个方法只会在App启动时运行,登出再登录后不会重新触发,所以菜单一直用的是第一次加载的旧数据。
下面是具体的修复方案,分步骤来:
1. 把菜单初始化逻辑抽成独立方法
首先在MyApp组件里,把原来写在initializeApp里的菜单赋值代码抽成一个单独的方法,这样我们可以在需要的时候(比如登录/登出后)手动调用它:
import { ChangeDetectorRef } from '@angular/core'; // 其他必要导入... export class MyApp { @ViewChild(Nav) nav: Nav; rootPage: any = authPage; appMenuItems: Array<MenuItem>; helpMenuItems: Array<MenuItem>; type: string; cin: any; id_en: any; pages: Array<{ title: string, component: any, icon: string }>; constructor( public platform: Platform, public statusBar: StatusBar, public splashScreen: SplashScreen, private app: App, public menu: MenuController, private cdr: ChangeDetectorRef // 注入变更检测服务 ) { this.initializeApp(); } initializeApp() { this.platform.ready().then(() => { this.statusBar.styleDefault(); this.splashScreen.hide(); // 初始化菜单 this.initMenu(); }); } // 新增:独立的菜单初始化方法 initMenu() { if (localStorage.getItem('id_en') !== null) { this.appMenuItems = [ {title: 'Nouveaux Annonces', component: NouveauxPubPage, icon: 'md-create'}, {title: 'Mes Annonces', component: HomeePage, icon: 'md-list-box'}, {title: 'Mes Etudiant', component: EtudiantPage, icon: 'ios-contacts'}, {title: 'Historique', component: HistoriquePage, icon: 'ios-undo'}, {title: 'A propos', component: exemplePage, icon: 'information-circle'}, ]; } else { this.appMenuItems = [ {title: 'Accueil', component: HomePage, icon: "md-home"}, {title: 'Stages', component: stagesPage, icon: "md-attach"}, {title: 'Nouveaux article', component: ETarticlePage, icon: "md-create"}, {title: 'Mes Articles', component: mesarticlePage, icon: "md-list-box"}, {title: 'Annonce', component: ETpubPage, icon: "md-clipboard"}, {title: 'Historique', component: EThistoriquePage, icon: "ios-undo"}, {title: 'Stage en cours', component: stage_en_courPage, icon: "md-alarm"}, {title: 'A propos', component: exemplePage, icon: 'information-circle'}, ]; } // 强制触发变更检测,确保菜单视图更新 this.cdr.detectChanges(); } openPage(page) { this.nav.setRoot(page.component); } deconnexionetudiant() { localStorage.removeItem('cin'); localStorage.removeItem('id_en'); localStorage.removeItem('type'); // 不要用window.location.reload,换成重新初始化菜单+跳转登录页 this.initMenu(); this.nav.setRoot(authPage); // 同时禁用菜单,直到新用户登录 this.menu.enable(false); } }
2. 在登录成功后触发菜单更新
在authPage的登录逻辑里,当用户登录成功并设置完localStorage后,需要通知App组件更新菜单。这里用Ionic的Events服务来实现,更优雅:
第一步:修改authPage代码
import { Events } from 'ionic-angular'; // 其他必要导入... export class authPage { resposeData: any; cin: number; emeil: String; result = <any[]>[]; data: any; activeMenu: string; constructor( public navCtrl: NavController, public authService: AuthService, private toastCtrl: ToastController, public menu: MenuController, private alertCtrl: AlertController, private events: Events // 注入Events服务 ) { this.menu.enable(false); } ionViewDidLoad() { if (localStorage.getItem('id_en') !== null) { this.navCtrl.setRoot(NouveauxPubPage); this.menu.enable(true); }else if(localStorage.getItem('cin') !== null) { this.navCtrl.setRoot(HomePage); this.menu.enable(true); } console.log('ionViewDidLoad Login'); } login() { console.log(this.cin, this.emeil); if (this.cin && this.emeil) { this.authService.auth(this.cin, this.emeil) .subscribe((data) => { this.result = data; if (this.result[1] == "enseignant") { this.navCtrl.setRoot(NouveauxPubPage); localStorage.setItem('id_en', data[0][0].id_en); localStorage.setItem('type', 'enseignant'); this.menu.enable(true); // 发送登录成功事件,通知App更新菜单 this.events.publish('user:loggedIn'); } else if (this.result[1] == "etudiant") { this.navCtrl.setRoot(HomePage); localStorage.setItem('cin', data[0][0].cin); localStorage.setItem('type', 'etudiant'); this.menu.enable(true); // 同样发送登录成功事件 this.events.publish('user:loggedIn'); } else { let alert = this.alertCtrl.create({ title: 'Erreur connexion', subTitle: "l'identifiant ou le mot de pass ne sont pas correcte", buttons: ['Ok'] }); alert.present(); console.log('error'); } }, (err) => { let alert = this.alertCtrl.create({ title: 'Erreur Serveur', subTitle: "Verifier votre internet", buttons: ['Ok'] }); alert.present(); console.log('error'); }); } } presentToast(msg) { let toast = this.toastCtrl.create({ message: msg, duration: 2000 }); toast.present(); } }
第二步:在MyApp组件里监听事件
回到MyApp组件,添加事件监听:
constructor( public platform: Platform, public statusBar: StatusBar, public splashScreen: SplashScreen, private app: App, public menu: MenuController, private cdr: ChangeDetectorRef, private events: Events // 注入Events服务 ) { this.initializeApp(); // 监听登录成功事件,触发菜单更新 this.events.subscribe('user:loggedIn', () => { this.initMenu(); }); }
3. 优化登出逻辑
之前的window.location.reload()会导致整个App重启,体验很差。我们已经在deconnexionetudiant方法里替换成了更友好的方式:清除本地存储后重新初始化菜单,再跳转到登录页,同时禁用菜单直到新用户登录。
这样修改后,切换用户时菜单就会根据新的用户类型自动更新了!
内容的提问来源于stack exchange,提问作者mohamed farjallah
相关产品推荐
相关产品推荐

