Node.js/Express/Handlebars导航栏active类动态切换问题
看起来你遇到的核心问题是前端JS设置的Active类在页面跳转/刷新后被重置了——因为点击导航链接后浏览器会重新请求页面,Handlebars会重新渲染模板,之前通过JS添加的类自然就没了。另外你当前的模板里默认只有Dashboard的<a>标签带active类,其他页面加载时不会自动匹配当前路由设置这个类,这才是关键。
先澄清一下你提到的<a> vs <li>的疑问:Bootstrap的nav-pills两种方式都支持——既可以给<li>加active类,也可以给<a>加active类,所以这个不是导致问题的原因,不用纠结这个点。
下面是具体的解决方案,分两步走:
1. 服务器端动态设置Active类(核心)
我们需要在Express路由中传递当前页面标识,然后在Handlebars模板里通过条件判断自动给对应导航项加上active类,这样页面加载时就会直接渲染正确的状态。
第一步:在路由中传递当前页面参数
修改你的Express路由,给每个页面的res.render方法添加currentPage变量,标识当前页面:
// 首页/Dashboard路由 app.get('/', (req, res) => { res.render('dashboard', { user: req.user, currentPage: 'dashboard' // 标识当前是dashboard页面 }); }); // 账户页面路由 app.get('/users/account', (req, res) => { res.render('account', { user: req.user, currentPage: 'account' // 标识当前是account页面 }); }); // 登录页面路由 app.get('/users/login', (req, res) => { res.render('login', { currentPage: 'login' // 标识当前是login页面 }); }); // 注册页面路由 app.get('/users/register', (req, res) => { res.render('register', { currentPage: 'register' // 标识当前是register页面 }); });
第二步:注册Handlebars比较助手
Handlebars默认没有相等比较的助手,所以我们需要注册一个eq助手来判断当前页面是否匹配:
// 在你的Express app初始化代码中添加 const hbs = require('hbs'); // 注册eq比较助手 hbs.registerHelper('eq', function(a, b) { return a === b; });
第三步:修改Handlebars模板动态设置Active类
更新layout.handlebars中的导航部分,用{{#if (eq currentPage 'xxx')}}active{{/if}}来动态添加类:
<div class="container"> <div class="header clearfix"> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">Home App</a> <ul id="navbarMenu" class="nav nav-pills"> {{#if user}} <li id="dashboardNav" class="nav-item"> <a class="nav-link {{#if (eq currentPage 'dashboard')}}active{{/if}}" href="/">Dashboard</a> </li> <li id="accountNav" class="nav-item"> <a class="nav-link {{#if (eq currentPage 'account')}}active{{/if}}" href="/users/account">Account</a> </li> <li id="logoutNav" class="nav-item"> <a class="nav-link" href="/users/logout">Logout</a> </li> {{else}} <li class="nav-item"> <a class="nav-link {{#if (eq currentPage 'login')}}active{{/if}}" href="/users/login">Login</a> </li> <li class="nav-item"> <a class="nav-link {{#if (eq currentPage 'register')}}active{{/if}}" href="/users/register">Register</a> </li> {{/if}} </ul> </nav> </div>
2. 修复前端JS的问题(可选,优化体验)
你之前的JS代码有个小问题:移除类的时候把nav-link也删掉了,这会导致导航样式失效。另外如果是单页操作(不跳转页面),可以保留JS来即时切换Active类,但如果是页面跳转的话,这段JS其实作用不大,不过还是可以优化一下:
<script type="text/javascript"> $('ul.nav-pills li a.nav-link').on("click", function() { // 移除所有导航项的active类 $('ul.nav-pills li a.nav-link').removeClass('active'); // 给当前点击的项添加active类 $(this).addClass('active'); }); </script>
这样修改后,不管是页面加载还是点击切换,导航栏的Active类都会正确显示,不会再出现加载后消失的问题了。
内容的提问来源于stack exchange,提问作者S.Q

