扒一个后台模板的源码,左侧菜单每一项都是 href 写着 javascript:; 的链接,点下去页面纹丝不动,地址栏也没变化。第一次见容易以为写错了,其实是老办法。

javascript: 是浏览器认的一种伪协议,写在 href 里表示后面这段当脚本执行。分号在 JS 里是一条空语句,执行完什么也不干,于是链接既不跳转也不刷新,只保留手型和下划线样式。

它解决的问题和留下的坑

早年前端靠 jQuery 绑 click,需要一个链接样子的元素来拿样式和键盘焦点,又不想真的跳页,就统一写成 javascript:;。坑在后面:用户右键在新标签页打开会得到空白页,复制链接发给别人,打开也是空白。

爬虫和 SEO 工具同样读不到真实地址,禁用 JS 之后这些菜单彻底点不动。控制台里偶尔还会看到 CSP 拦截内联脚本的报错,指向的就是这类写法。

还有个近亲 javascript:void(0),作用一样,void 后面跟 0 表示返回 undefined。老代码里两种写法混着出现,别以为是两个功能。

现在更稳的三种写法

  • 纯操作按钮用 button type=button,语义对,回车和空格都能触发,默认不提交表单。
  • 必须用链接就写真实地址,再用 event.preventDefault() 拦掉跳转,比伪协议好调试。
  • 临时占位写 href=# 也行,但点击会把页面顶回顶部,还往历史记录里塞一条,需要一并拦住。

伪协议写法和 href=# 有个隐性差别:前者不往浏览历史里加记录,后者会。用户按返回键,一个原地不动,一个退回到上一个井号,测试时容易漏。如果接手的老项目里到处是 javascript:;,不用急着全改。先把真正的导航链接换成地址,剩下的操作项挑重点页面逐步换成 button,改一处测一处,比一次性重写安全。

还有一个细节:键盘用户按 Tab 能聚焦,按回车却不响应,问题往往出在绑定的是 click 而不是 keydown。换成原生按钮这类问题自然消失,这也是我优先推荐 button 的原因。