
JS动态创建的img、script等元素完全无视<base>
无论你在里写了<base href="/admin/">还是<base href="https://cdn.example.com/">,用 JS 动态创建的资源路径解析逻辑完全不变——它只看当前页面 URL,不读document.baseURI(除非你显式用它)。
常见错误现象:
-
document.createElement('img').src = 'logo.png'→ 请求的是当前页面同目录下的logo.png,不是/admin/logo.png -
element.style.backgroundImage = "url(bg.jpg)"→ 按 CSS 文件所在位置解析,和<base>无关 - 页面部署在
https://example.com/app/sub/,但new Image().src = 'icon.svg'仍发请求到/app/sub/icon.svg,而非/app/icon.svg
fetch()、import()、new Worker()全都不受<base>控制
这些 API 的路径解析规则由运行时环境决定,与 HTML 解析阶段的<base>标签彻底隔离。它们遵循模块规范或 Fetch 标准,以调用者所在脚本的 URL 为基准。
使用场景与要点:
-
fetch('./api/user')→ 相对于当前 JS 文件路径,不是document.baseURI -
import('./utils.js')→ 以该 import 语句所在模块位置为起点,Webpack/Vite 构建时会按publicPath或build.base重写,但运行时不查<base> -
new Worker('./worker.js')→ 同样基于 worker 脚本引用处的文件位置,<base>无效 - 即使
document.baseURI返回"https://example.com/v2/",fetch('data.json')也绝不会自动变成https://example.com/v2/data.json
真正要用document.baseURI时,得手动构造
document.baseURI确实会反映<base href>的值,但它只是个只读字符串,不会自动参与任何路径拼接。想让它起作用,必须显式调用 new URL() 或字符串拼接。
实操建议:
- 需要统一前缀的动态请求?写个封装函数:
function api(path) { return new URL(path, document.baseURI).href; },再传给fetch(api('user')) - 避免硬编码:如果
<base>可能为空或未设,先判断document.baseURI !== document.URL再用 - 不要依赖
document.baseURI做路由跳转——window.location.href = document.baseURI + '#section'会破坏锚点行为,且不兼容 history API - Vite/React/Vue 项目中,更推荐用环境变量或构建时注入的
import.meta.env.BASE_URL,它比document.baseURI更可控、可 Tree-shake
为什么开发者总在这儿踩坑
因为<base>对<img src="x">生效太“直观”,让人误以为它是全局路径代理。但 JS 运行时路径解析是另一套机制,浏览器从不把<base>注入到 fetch/import 的底层逻辑里。
最容易被忽略的一点:CSS 中的background: url(avatar.jpg)在 HTML 解析阶段就受<base>影响(注意是 HTML 解析时计算,不是 CSS 引擎运行时 resolve),而 JS 里的element.style.backgroundImage却完全绕过——同一张图,两种写法,路径行为截然不同。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











