AngularJS ui-router嵌套路由异常:指定ui-sref触发双模板加载求解决
看起来你遇到的问题是因为两个同级子状态的URL模式冲突,或者没有明确指定模板要插入的目标ui-view,导致触发其中一个状态时,另一个状态的模板也被意外加载了。下面是具体的解决步骤:
问题分析
你的practice.exam.service.competitiveSamplePaper和practice.exam.service.subject都是practice.exam.service的同级子状态,但它们的URL都使用了无区分度的动态参数({samplePaperNumber}和{subjectName}),ui-router无法通过URL模式精准区分这两个状态;另外,如果没有明确指定views配置,子状态的模板可能会被错误地插入到父状态的ui-view中,甚至因为状态匹配逻辑导致两个状态同时被激活。
解决方案
方案1:给子状态添加唯一的URL前缀
给两个子状态的URL添加不同的静态前缀,让它们的URL模式明确区分,这样ui-router就能精准匹配到目标状态:
$stateProvider .state('main', { url:'/', templateUrl:'views/main.html', controller:'MainCtrl' }) .state('practice', { url:'/practice', templateUrl:'views/practice/practice.html', controller:'PracticeCtrl' }) .state('practice.exam', { url:'/{examName}', templateUrl:'views/practice/exam.html', controller:'ExamCtrl' }) .state('practice.exam.service', { url:'/{serviceName}', templateUrl:'views/practice/service.html', controller:'ServiceCtrl' }) // 给competitiveSamplePaper添加/sample前缀 .state('practice.exam.service.competitiveSamplePaper', { url:'/sample/{samplePaperNumber}', templateUrl:'views/practice/competitive_sample_paper.html', controller:'CompetitiveSamplePaperCtrl' }) // 给subject添加/subject前缀 .state('practice.exam.service.subject', { url:'/subject/{subjectName}', templateUrl:'views/practice/subject.html', controller:'SubjectCtrl' })
这样,跳转practice.exam.service.subject({subjectName: 'Physics'})时,URL会是/practice/{examName}/{serviceName}/subject/Physics,不会和competitiveSamplePaper的URL模式混淆,也就只会加载对应的subject模板。
方案2:明确指定子状态的目标ui-view
如果不想修改URL结构,可以通过views配置明确指定每个子状态的模板要插入到父状态的哪个ui-view中,确保每次只有一个子模板被加载:
首先,在practice.exam.service的模板(views/practice/service.html)中,给ui-view指定一个名称:
<!-- views/practice/service.html --> <div ui-view="content"></div>
然后修改状态定义,给每个子状态添加views配置:
$stateProvider .state('main', { url:'/', templateUrl:'views/main.html', controller:'MainCtrl' }) .state('practice', { url:'/practice', templateUrl:'views/practice/practice.html', controller:'PracticeCtrl' }) .state('practice.exam', { url:'/{examName}', templateUrl:'views/practice/exam.html', controller:'ExamCtrl' }) .state('practice.exam.service', { url:'/{serviceName}', templateUrl:'views/practice/service.html', controller:'ServiceCtrl' }) .state('practice.exam.service.competitiveSamplePaper', { url:'/{samplePaperNumber}', views: { // 指定插入到practice.exam.service状态下的content ui-view 'content@practice.exam.service': { templateUrl:'views/practice/competitive_sample_paper.html', controller:'CompetitiveSamplePaperCtrl' } } }) .state('practice.exam.service.subject', { url:'/{subjectName}', views: { 'content@practice.exam.service': { templateUrl:'views/practice/subject.html', controller:'SubjectCtrl' } } })
这种方式下,两个子状态的模板都会替换同一个命名ui-view,触发跳转时只会加载对应状态的模板,不会同时加载两个。
方案3:检查状态激活逻辑
最后,确认你的代码中没有同时触发两个状态的跳转操作,比如是否有额外的$state.go调用,或者ui-sref是否误写了多个状态名称。
内容的提问来源于stack exchange,提问作者Nitish Kumar




