原生JS路由
写JS原生路由时可从以下几个方面入手
- 监听a标签,并给href里的url加锚点链接
一般情况下菜单栏的加载模式中,都是通过<a>中的href='/xxxx'来跳转到指定的页面,所以路由的第一步就是监听到此菜单栏中<a
href='/xxx'>`的点击事件,并在点击时通过event.preventDefault()阻止浏览器的默认行为。阻止默认行为后,咱们就可以通过#/index这种形式给拿到的url加锚
- 监听hashchange事件,并在监听被触发时加载对应的页面
通过hashchange函数来监听加了锚之后的url(即hash),监听到hash的变化后,我们可以拿到点击时的url,通过调用Router(params)时传入的params参数来找到此文件的静态路径,然后传入到iframe
的 src中。
- 在Router调用时添加目标容器,添加首页加载
在这个例子中使用的内容容器是个iframe,所以我需要考虑多个iframe嵌套下的Loader目标(target)问题,当然,首页也是需要可以设置默认加载的。
代码示例:
1.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="description">
<title>Document</title>
<style>
@import url('https://fonts.googleapis.com/css?family=Montserrat:400,400i,700');
a {
text-decoration: none;
background: white;
border-radius: 10px;
padding: .5em 1em;
font-weight: bold;
}
body {
display: grid;
grid-template-columns: auto 1fr;
min-height: 100vh;
margin: 0;
font-family: 'Montserrat';
}
nav {
display: flex;
flex-direction: column;
background: #f1f1f1;
padding: 3.2rem 1rem;
gap: 1rem;
}
#root {
padding: 2rem;
max-width: min(75ch, 90%);
margin-inline: auto;
}
</style>
</head>
<body>
<nav>
<a href="/">Home</a>
<a href="/about">About Us</a>
<a href="/services">Our Services</a>
<a href="/contact">Contact Us</a>
</nav>
<div id="root"></div>
<script src="app.js"></script>
</body>
</html>
2.app.js
const siteTitle = 'A Fabulous Company'
const routes = {
404: {
page: '/pages/404.html',
title: '404 | ' + siteTitle,
description: 'Page not found'
},
'/': {
page: '/pages/home.html',
title: 'Home | ' + siteTitle,
description: 'Home Page'
},
'/about': {
page: '/pages/about.html',
title: 'About Us | ' + siteTitle,
description: 'About Us'
},
'/services': {
page: '/pages/services.html',
title: 'Our Services | ' + siteTitle,
description: 'Our Services'
},
'/contact': {
page: '/pages/contact.html',
title: 'Contact Us | ' + siteTitle,
description: 'Contact Us'
}
}
document.querySelector('nav').addEventListener('click', (e) => {
if (e.target.matches('a')) {
e.preventDefault()
useRoute()
}
})
const useRoute = (e) => {
e = e || window.event
e.preventDefault()
window.history.pushState({page: window.location.pathname}, '', e.target.href)
renderPage()
}
const renderPage = async () => {
const location = window.location.pathname
const route = routes[location] || routes[404]
const response = await fetch(route.page)
const data = await response.text()
document.querySelector('#root').innerHTML = data
document.title = route.title
document.querySelector('meta[name="description"]')
.setAttribute('content', route.description)
}
window.onpopstate = renderPage
window.useRoute = useRoute
renderPage()
(代码借鉴上面链接)