前端路由与单页页面
路由就是指随着浏览器地址栏的变化,展示给用户的页面也不相同。
传统的网页根据用户访问的不同的地址,浏览器从服务器获取对应页面的内容展示给用户。这样造成服务器压力比较大,而且用户访问速度也比较慢。在这种场景下,出现了单页应用。
单页应用(spa),就是只有一个页面,用户访问一个网址,服务器返回的页面始终只有一个,不管用户改变了浏览器地址栏的内容或者在页面内发生了跳转,服务器不会重新返回新的页面,而是通过相应的js操作来实现页面的更改。而地址栏内容的改变,显示不同的页面,实现的手段就是前端路由。
前端路由是现代SPA应用必备的功能,每个现代前端框架都有对应的实现,例如vue-router、react-router。
我们不去探究vue-router或者react-router们的实现,因为不管是哪种路由无外乎用兼容性更好的hash实现或者是H5 History实现,与框架几个只需要做相应的封装即可。
前端路由的简单实现方式
我们经常在 url 中看到 #,这个 # 有两种情况,一个是我们所谓的锚点,比如典型的回到顶部按钮原理、Github 上各个标题之间的跳转等,但是路由里的 # 不叫锚点,我们称之为 hash。
现在的前端主流框架的路由实现方式都会采用 Hash 路由,本项目采用的也是。
当 hash 值发生改变的时候,我们可以通过 hashchange 事件监听到,从而在回调函数里面触发某些方法。。
hash+hashchange实现
这种方法的好处在于支持IE浏览器。对早期的一些浏览器的支持比较好。
实现原理:
location.hash始终指向页面url 中#之后的内容
当当前页面的url =’www.baidu.com’,可以在浏览器的控制台输入location.hash为空,当页面指向url =’www.baidu.com/#/hello’的时候,location.hash = ‘#/hello’。通过读取location.hash可以知道当前页面所处的位置。通过hashchange事件可以监听location.hash的变化,从而进行相应的处理即可。
那么如何触发hash的改变呢?这里主要由两种方法:
设置a标签,href = ‘#/blue’,当点击标签的时候,可以在当前url的后面增加上’#/blue’,同时触发hashchange,再回调函数中进行处理。
另外 直接在js中对location.hash = ‘#/blue’即可,此时url会改变,也会触发hashchange事件。
下面我们自己实现一个前端路由
<a href="#/home" class="router">home</a>
<!-- 导航 -->
<div class="router_box">
<a href="#/home" class="router">主页</a>
<a href="#/news" class="router">新闻</a>
</div>
<!-- 页面中显示内容的部分 -->
<div id="router-view"></div>
// 配置不同的路由 要显示的页面内容
let routes = [{
path: '#/home',
page: `
<h1>我是首页</h1>
`
}, {
path: '#/news',
page: `
<h1>我是新闻页面</h1>
`
}]
// 监听hashchange 变化,一旦有变化,意味着可能要改变页面显示的内容
window.addEventListener("hashchange", () => {
// 获取变化以后的hash
let nowHash = window.location.hash;
console.log(nowHash)
// 去路由配置中查找是否配置过这个路由,并找到这个路由配置
let routeConfig = routes.find((item, index) => {
return nowHash == (item.path);
});
console.log(routeConfig)
if (routeConfig) {
// 如果存在这个配置 就把配置中要显示的内容显示到页面上
document.querySelector("#router-view").innerHTML = routeConfig.page;
}
});
把上面的代码封装一下
class MyVueRouter {
constructor({
routes
}) {
// 监听hashchange 变化,一旦有变化,意味着可能要改变页面显示的内容
window.addEventListener("hashchange", () => {
// 获取变化以后的hash
let nowHash = window.location.hash;
console.log(nowHash, routes)
// 去路由配置中查找是否配置过这个路由,并找到这个路由配置
let routeConfig = routes.find((item, index) => {
return nowHash == (item.path);
});
console.log(routeConfig)
if (routeConfig) {
// 如果存在这个配置 就把配置中要显示的内容显示到页面上
document.querySelector("#router-view").innerHTML = routeConfig.page;
}
});
}
}
let router = new MyVueRouter({
routes: [{
path: '#/home',
page: `
<h1>我是首页</h1>
`
}, {
path: '#/news',
page: `
<h1>我是新闻页面</h1>
`
}]
})