实现方式核心在于使用hashchange 事件监听浏览器切换界面请求,更改浏览器地址后渲染新的组件(实际上加#的原因是因为a标签加了#就不会进行页面跳转?)
a 标签锚点大家应该不陌生,而浏览器地址上 # 后面的变化,是可以被监听的,浏览器为我们提供了原生监听事件 hashchange ,它可以监听到如下的变化:
点击 a 标签,改变了浏览器地址
浏览器的前进后退行为
通过 window.location 方法,改变浏览器地址
接下来我们利用这些特点,去实现一个hash模式的简易路由
思路:通过hashchange函数监听路由的变化 切换新的组件
- html
- 定义三个元素
- 两个a标签 (href加上#,阻止默认的跳转行为)
- 一个类为router-view的div(用于模拟挂载的组件)
- js
- 获取id为router-view的元素
- 定义 HashChange()函数 根据当前的url地址切换需要切换的组件 使用 switch判定切换
DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Hash 模式title> head> <body> <div> <ul> <li><a href="#/page1">page1a>li> <li><a href="#/page2">page2a>li> ul> <div id="route-view">div> div> <script type="text/javascript"> // 第一次加载的时候,不会执行 hashchange 监听事件,默认执行一次 // DOMContentLoaded 为浏览器 DOM 加载完成时触发 window.addEventListener('DOMContentLoaded', Load) window.addEventListener('hashchange', HashChange) // 展示页面组件的节点 var routeView = null function Load() { routeView = document.getElementById('route-view') HashChange() } function HashChange() { // 每次触发 hashchange 事件,通过 location.hash 拿到当前浏览器地址的 hash 值 // 根据不同的路径展示不同的内容 switch(location.hash) { case '#/page1': routeView.innerHTML = 'page1' return case '#/page2': routeView.innerHTML = 'page2' return default: routeView.innerHTML = 'page1' return } } script> body> html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
浏览器展示效果如下:
核心在于 popstate事件(在网页回退前进或js手动触发代码时会调用)我们再这个事件调用时触发回调函数,根据当前url切换组件。
问题在于不是写了这个就行,因为有些事件不会触发这个回调函数,比如a标签的跳转,我们要做的就是,阻值a标签默认动作后,加上点击事件的回调函数,在回调函数内获取 a 标签的 href 属性值,使用pushState、replaceState修改url,再手动触发popstate的回调函数更改显示的组件
思路:通过popstate事件监听路由的变化 切换新的组件
- html
- 定义三个元素
- 两个a标签 (href加上#,阻止默认的跳转行为)
- 一个类为router-view的div(用于模拟挂载的组件)
- js
- 初始化时 获取所有的a标签元素 进行遍历,添加被点击时的回调函数
- 阻止默认的页面跳转事件
- 获取要跳转的地址 手动调用 history.pushState()和history.replaceState()修改url地址 然后调用后面定义的PopChange()函数
- 获取id为router-view的元素
- 定义 PopChange()函数 根据当前的url地址切换需要切换的组件 使用 switch判定切换
DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>History 模式title> head> <body> <div> <ul> <li><a href="/page1">page1a>li> <li><a href="/page2">page2a>li> ul> <div id="route-view">div> div> <script type="text/javascript"> window.addEventListener('DOMContentLoaded', Load) window.addEventListener('popstate', PopChange) var routeView = null function Load() { routeView = document.getElementById('route-view') // 默认执行一次 popstate 的回调函数,匹配一次页面组件 PopChange() // 获取所有带 href 属性的 a 标签节点 var aList = document.querySelectorAll('a[href]') // 遍历 a 标签节点数组,阻止默认事件,添加点击事件回调函数 aList.forEach(aNode => aNode.addEventListener('click', function(e) { e.preventDefault() //阻止a标签的默认事件 var href = aNode.getAttribute('href') // 手动修改浏览器的地址栏 history.pushState(null, '', href) // 通过 history.pushState 手动修改地址栏, // popstate 是监听不到地址栏的变化,所以此处需要手动执行回调函数 PopChange PopChange() })) } function PopChange() { console.log('location', location) switch(location.pathname) { case '/page1': routeView.innerHTML = 'page1' return case '/page2': routeView.innerHTML = 'page2' return default: routeView.innerHTML = 'page1' return } } script> body> html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53