Vue-Router有两种模式:hash模式和history模式。默认的路由模式是hash模式。
hash模式
特点: hash值会出现在URL里面,但是不会出现在HTTP请求中,对后端完全没有影响。hash值变化对应的URL都会被浏览器记录下来,这样浏览器就能实现页面的前进和后退。虽然是没有请求后端服务器,但是页面的hash值和对应的URL关联起来了。
原理: hash模式的主要原理就是window对象上的onhashchange()事件
模拟hash模式下单页页面应用
<body>
<ul>
<li><a href="#/home">首页</a></li>
<li><a href="#/about">关于</a></li>
</ul>
<div id="routeView"></div>
<script>
const routes = [
{
path: "/home",
component: `<div class='home-page'>首页</div>`,
},
{
path: "/about",
component: `<div class='about-page'>关于页面</div>`,
},
{
path: "/:pathMatch(.*)",
component: `<div class='not-found'>404页面</div>`,
},
];
// 初始化时执行
window.addEventListener("DOMContentLoaded", onHashChange);
window.addEventListener("hashchange", onHashChange);
function onHashChange() {
let findRoute = routes.find(
(route) => `#${route.path}` === location.hash
);
if (!findRoute) {
findRoute = routes[routes.length - 1];
}
document.querySelector("#routeView").innerHTML = findRoute.component;
}
</script>
</body>
history模式
特点: 当使用history模式时,URL就像这样:abc.com/user/id。相比hash模式更加好看。但是,history模式下,获取页面资源时,会拼接url中的pathname(/user/id)作为整体请求,如果后台没有正确配置(譬如ngnix设置location重定向),访问时会返回404。另外浏览器前进后退时,也需要监听popstate特殊处理,否则无法管理到具体页面。
原理: 运用history对象上的 pushState() 和 replaceState() 方法,提供了对历史记录进行修改的功能,虽然修改了url,但浏览器不会立即向后端发送请求;浏览器前进后退时,也需要监听window对象上的popstate特殊处理。
模拟 history模式下单页页面应用
<body>
<ul>
<li><a href="/home">首页</a></li>
<li><a href="/about">关于</a></li>
</ul>
<div id="routeView"></div>
<script>
const routes = [
{
path: "/home",
component: `<div class='home-page'>首页</div>`,
},
{
path: "/about",
component: `<div class='about-page'>关于页面</div>`,
},
{
path: "/:pathMatch(.*)",
component: `<div class='not-found'>404页面</div>`,
},
];
window.addEventListener("DOMContentLoaded", onLoad);
// 浏览器的前进后退
window.addEventListener("popstate", renderComponent);
function onLoad() {
const links = document.querySelectorAll("li a"); // 获取所有的li下的a标签
links.forEach((a) => {
a.addEventListener("click", (e) => {
e.preventDefault(); // 阻止a的跳转行为
history.pushState(null, "", a.getAttribute("href"));
// 映射对应的dom
renderComponent();
});
});
}
function renderComponent() {
let findRoute = routes.find(
(route) => `${route.path}` === location.pathname
);
if (!findRoute) {
findRoute = routes[routes.length - 1];
}
document.querySelector("#routeView").innerHTML = findRoute.component;
}
</script>
</body>