Ember路由跳转后URL更新但对应模板未渲染问题排查
问题根因
路由跳转后URL变化但页面不渲染的问题,是3个核心错误叠加导致的:
- 最核心的问题:根模板
application.hbs缺少路由渲染占位符{{outlet}},且登录组件放置的模板位置错误 - 表单未阻止默认提交行为,触发浏览器原生表单刷新逻辑,打断了Ember的单页路由渲染流程
- 跳转逻辑使用了冗余的私有API写法,重复触发路由跳转导致状态异常
具体修复步骤
1. 调整模板层级,补全路由占位符
Ember的路由渲染规则是:所有子路由的模板,都会渲染到上层模板的{{outlet}}占位符位置。
- 首先修改
app/templates/application.hbs,这个是全局根模板,只需要保留outlet占位,不要直接放登录组件:
{{!-- application.hbs 内容 --}} {{outlet}}
- 把之前写在application.hbs里的
<Auth />组件,移动到根路径对应的index路由模板app/templates/index.hbs里(如果没有这个文件就新建):
{{!-- app/templates/index.hbs 内容 --}} <Auth />
调整后跳转路由时,index路由对应的登录组件会被自动替换成目标路由的模板,不会一直停留在页面上。
2. 阻止表单默认提交行为
原生form标签的submit事件默认会触发页面刷新,会直接打断Ember的单页路由逻辑。修改auth.hbs的表单标签,给action加阻止默认行为的修饰符:
{{!-- auth.hbs 对应修改部分 --}} <form {{action "buttonClick" on="submit" preventDefault=true}}> <div class="text-field"> <label>UserName:</label> <Input type="text" id="username" required /> <span></span> </div> <div class="text-field"> <label>Password:</label> <Input type="password" id="password" required /> <span></span> </div> <div id="result"></div> <input type="submit" value="Login"> </form>
把原来绑在submit input上的action移到form标签上,加preventDefault=true就可以直接拦截原生刷新行为。
3. 清理冗余的路由跳转代码
当前使用的Octane版本Ember(采用@glimmer/component、装饰器写法),不需要用老版本的this.get()写法,也不需要访问router服务的内部私有属性router.router,重复调用跳转方法还会导致路由状态混乱。修改auth.js里的buttonClick方法:
// auth.js 对应修改部分 @action buttonClick() { let username = document.getElementById('username').value; let password = document.getElementById('password').value; console.log('user is ' + username); // 直接调用router服务的公开API跳转即可,不需要冗余变量和私有属性访问 this.router.transitionTo('demo'); // 如果不需要登录页留在浏览器历史记录,可以换成 this.router.replaceWith('demo') }
验证
改完以上三点后,点击登录按钮就会正常跳转到demo路由,页面会自动渲染demo路由model中返回的三个post标题内容,不会再停留在登录页。
补充:后续优化可以把直接操作DOM拿input值的写法换成Ember的响应式数据绑定,避免直接操作DOM带来的问题,不过这个不影响当前路由跳转功能的正常使用。
内容的提问来源于stack exchange,提问作者tgb
相关产品推荐
相关产品推荐

