简介
路由是什么,简单来说根据不同URL地址访问不同的内容。在以前路由这一功能都是在服务器端实现的,一个页面对应着一个URL地址,由服务端根据URL响应不同的页面给浏览器,这是多页面跳转。
前端的路由因为在浏览器端完成的,所以这是一个单页面的跳转技术,根据URL的变化显示页面不同的内容。
前端路由有两种:hash路由、history路由。
hash路由
hash路由就是根据URL的hash部分的变化显示不同的内容或组件。
URL的hash部分
我们知道一个完整的URL有以下几个部分:协议、端口、域名、虚拟目录以及文件路径、参数、锚。
如:http://localhost:5173/index/index.html?id=1#title
http就是协议,localhost就是域名,5173是端口,index/index.html是虚拟目录以及文件路径,这一部分如果没有就是网站的根目录,?后面的是参数,#后面的是锚部分也叫hash部分。
因为锚链接是跳转到当前页id为对应hash值的元素位置,只会在本页面上进行跳转,所以可以根据监测URL的hash部分的变化就可以切换不同的内容。
hashchange事件就是当hash值发生变化时执行的事件。
实现代码如下,过程都在注释当中:
<div id="app">
<!-- hash路由切换的锚链接, #后面就是hash值 -->
<nav>
<a href="#index">首页</a>
<a href="#list">列表页</a>
<a href="#contact">联系我们</a>
</nav>
<!-- hash路由切换显示的区域 -->
<div class="router-view">
</div>
</div>
<script>
// 获取显示组件的容器
const routerViewBox = document.querySelector(".router-view");
// 模拟创建组件的方法,创建一个组件容器元素然后设置好HTML以及命名。
function createComponent(componentName, componentTemplate) {
const div = document.createElement("div");
div.dataset.name = componentName;
div.innerHTML = componentTemplate;
return div;
}
// 创建首页组件
function Index() {
const template = `
<h1>我是首页</h1>
<p>欢迎来个学习前端知识</p>
`;
return createComponent("index", template);
}
// 创建列表页组件
function List() {
const template = `
<ul>
<li>学习HTML</li>
<li>学习CSS</li>
<li>学习JavaScript</li>
<li>学习Node.js</li>
<li>学习Vue</li>
<li>学习React</li>
</ul>
`;
return createComponent("list", template);
}
// 创建联系我们组件
function Contact() {
const template = `
<article>
<p>地址:xxxxxxxxxx</p>
<p>邮箱:xxxxxxxxxx</p>
<p>电话:xxxxxxxxxx</p>
</article>
`;
return createComponent("contact", template);
}
function Error404() {
const template = `<div>404, 非法路由</div>`;
return createComponent("error404", template);
}
// 模拟渲染组件,通过hash的值渲染
function renderer() {
const hash = location.hash.slice(1); // 获取URL的hash的值
routerViewBox.innerHTML = ""; // 清空显示区域的HTML。
// 根据hash的值渲染不同的组件
switch (hash) {
case "": //首次加载的值
case "index":
routerViewBox.appendChild( Index() )
break;
case "list":
routerViewBox.appendChild( List() )
break;
case "contact":
routerViewBox.appendChild( Contact() )
break;
default:
routerViewBox.appendChild( Error404());
break;
}
}
// 地址栏 hash变化事件
window.onhashchange = () => {
renderer();
}
renderer(); // 首次加载渲染组件
</script>
history路由
history是根据浏览器的历史记录来控制显示不同内容的,使用history.pushState方法在历史记录中添加新的历史记录,然后渲染新的显示内容。
<div id="app">
<!-- hash路由切换的链接 -->
<nav>
<a href="/index">首页</a>
<a href="/list">列表页</a>
<a href="/contact">联系我们</a>
</nav>
<!-- hash路由切换显示的区域 -->
<div class="router-view">
</div>
</div>
<script>
const routerViewBox = document.querySelector(".router-view");
// 模拟创建组件的方法
function createComponent(componentName, componentTemplate) {
const div = document.createElement("div");
div.dataset.name = componentName;
div.innerHTML = componentTemplate;
return div;
}
// 模拟首页组件
function Index() {
const template = `
<h1>我是首页</h1>
<p>欢迎来个学习前端知识</p>
`;
return createComponent("index", template);
}
// 模拟列表页组件
function List() {
const template = `
<ul>
<li>学习HTML</li>
<li>学习CSS</li>
<li>学习JavaScript</li>
<li>学习Node.js</li>
<li>学习Vue</li>
<li>学习React</li>
</ul>
`;
return createComponent("list", template);
}
// 模拟联系我们组件
function Contact() {
const template = `
<article>
<p>地址:xxxxxxxxxx</p>
<p>邮箱:xxxxxxxxxx</p>
<p>电话:xxxxxxxxxx</p>
</article>
`;
return createComponent("contact", template);
}
// 模拟渲染组件
function renderer() {
const pathname = location.pathname;
routerViewBox.innerHTML = "";
switch (pathname) {
case "/index":
routerViewBox.appendChild( Index() )
break;
case "/list":
routerViewBox.appendChild( List() )
break;
case "/contact":
routerViewBox.appendChild( Contact() )
break;
default:
routerViewBox.appendChild( Index() )
break;
}
}
// 使用事件代理监听 a 标签的点击事件
document.querySelector("nav").addEventListener("click", e => {
if(e.target.nodeName === "A") { // 如果点击的是 A 标签
const href = e.target.getAttribute("href"); // 获取 A 标签的 href 属性
history.pushState({name: "首页", path: "/index"}, "", href); // 添加历史记录
renderer(); // 渲染组件
e.preventDefault(); // 阻止A标签的默认跳转行为
}
})
renderer();
</script>
Vue路由简介
Vue Router是基于Vue的组件系统构建的路由插件,可通过配置来告诉Vue Router为每个URL路径显示哪些组件,还提供其它额外的功能,如:路由守卫、动态路由等,下一节开始正式讲解Vue Router的使用。