这是我参与更文挑战的第9天,活动详情查看: 更文挑战
VueRouter总结
单页面的跳转核心思想:改变 url 不刷新页面
VueRouter总共分为三种模式
- Hash模式
- History模式
- abstract模式 (abstract 模式针对的是没有浏览器环境的情况. 比如 Weex 客户端开发,内部是没有浏览器 API 的,那么 Vue-Router 自身会对环境做校验,强制切换到 abstract 模式,如果默认在 Vue-Router 的配置项中不写 mode 的值,在浏览器环境下会默认启用 Hash 模式,在移动客户端下使用 abstract 模式。)
Hash模式
特点
- 是VueRouter的默认模式
- 浏览器的兼容性强,甚至可以兼容低版本的IE浏览器
- 比History模式要更方便在服务器端部署,因为没有URL重定向的问题
- 运用在了单页面开发的路由模式上(只在一个页面切换对应组件就行)
- 地址栏里有个
#号 #号后面内容的改变,不会引起页面对服务端的请求,所以也就不会重新加载页面。
应用场景
浏览器上看到这样一种场景,点击某个文字,网页会跳转到某一个固定的位置,并且页面不会刷新。这便是浏览器的 a 标签锚点。Hash 模式被运用在了单页面开发的路由模式上,下面我们来简单实现一个通过 Hash 去控制页面组件的展示。
Hash 模式被运用在了单页面开发的路由模式上,下面我们来简单实现一个通过 Hash 去控制页面组件的展示。 浏览器原生方法为我们提供了一个监听事件 hashchange,它能监听到的改变如下:
- 点击 a 标签改变 URL 地址;
- 浏览器的前进后退行为;
- 通过
window.location方法改变地址栏;
hashchange:HTML5增加了hashchange 事件,用于在URL散列值(URL最后# 后面的部分)发生变化时通知开发者。也就是说每次URL的散列值变化的时候这个事件都会触发。
案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
<ul>
<!-- 因为是锚点,所以点击还是在当前页面 -->
<li><a href="#/page1">page1</a></li>
<li><a href="#/page2">page2</a></li>
</ul>
<div id="route-view"></div>
</div>
<script type="text/javascript">
//当HTML文档被完全加载和解析完成后
window.addEventListener("DOMContentLoaded",Load)
//当地址栏发生变化的时候触发hashchange
window.addEventListener("hashchange",HashChange)
var routeView = null;
function Load(){
routeView = document.getElementById('route-view');
// console.log('routeView_1',routeView);
// console.log("1")
//网页加载完成后先调用一次hashchange函数
HashChange();
}
function HashChange(){
console.log('location.hash',location.hash);
switch(location.hash){
case '#/page1':
routeView.innerHTML = 'page1'
return
case '#/page2':
routeView.innerHTML = 'page2'
return
default:
routeView.innerHTML = 'page1'
console.log('routeView',routeView);
return
}
}
</script>
</body>
</html>
div的routeview:告诉你当前在哪块
page1,page2: 相当于页面的容器组件
首先页面加载完成后,触发load函数,因为浏览器加载完成是不执行hashchange的,下面要显示一个默认在哪个页面,所以要在load函数里执行HashChange。然后点击a标签跳转锚点,因为是a标签锚点,所以点击实际还是在当前页面,根据a标签的href改变了URL的散列值(也就是#后内容),自动触发了hashchange事件,然后触发HashChange,然后根据URL的散列值给id为route-view的div改值。可以改值 也可以干很多事情 只不过是这个案例仅仅改值。
location.hash是什么
比如当前的URL是https://anblog.top#2333回车 在控制台输入
location.hash
//"#2333"
Histroy模式
特点
- 无法监听到pushState 、replaceState、 a标签这三种变化。
- 可以监听到浏览器的前进和后退。
- 好看,没有
# - 需要和后端配合,不然就是404.
vue-router默认hash模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。
如果觉得hash有#很丑,我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。
无法监听到pushState 、replaceState、 a标签这三种变化的解决方法:把页面上的a标签全部遍历一次,阻止a标签的默认事件
实现一个案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
<ul>
<li><a href="/page1">page1</a></li>
<li><a href="/page2">page2</a></li>
</ul>
<div id="route-view"></div>
</div>
<script>
//页面加载完毕后执行load
window.addEventListener('DOMContentLoaded',load)
//声明PopChange为popstate的回调函数 每次触发popstate就会执行PopChange
window.addEventListener('popstate',PopChange)
var routeView = null
function load(){
routeView = document.getElementById('route-view')
PopChange()
// 获取所有有href属性的a标签节点
var aList = document.querySelectorAll('a[href]')
//遍历a标签节点数组,组织默认事件,添加点击事件回调函数
//foreach对数组每一项都运行传入的函数,没有返回值
aList.forEach(aNode => aNode.addEventListener('click',function(e){
e.preventDefault();//阻止a标签的默认事件
var href = aNode.getAttribute('href')
//浏览器对象history history.pushState(state,title,url)
// 可以让开发者改变浏览器URL而不会加载新页面。为此,可以使用history.pushState() 方法。
//state: 一个与指定网址相关的状态对象,popState事件触发时,该对象会传入回调函数。如果不需要这个对象,可填null
//title: 新页面的标题,但是所有浏览器都忽略这个值,可填null
//url: 新的网址,必须与当前页面处在同一个域
history.pushState(null, null, href)
PopChange()
}))
}
//改变那个div的显示
function PopChange() {
//window的location属性
//window.location.href 返回当前页面的 href (URL)
// window.location.hostname 返回 web 主机的域名
// window.location.pathname 返回当前页面的路径或文件名
// window.location.protocol 返回使用的 web 协议(http: 或 https:)
// window.location.assign 加载新文档
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>
通过案例可以发现,给a标签都绑定上回调函数,每次点击a标签执行回调函数,同时执行的回调函数内还有popstate的回调函数PopChange()。popstate主要是监听除了pushState 、replaceState之外的地址栏变化(比如location.hash变了,或者浏览器前进后退都会触发),通过history.pushState把url拼接好。然后用回调函数进行页面id为route-view的div的修改。但所有的前提是做好配置,如果没有配置好后端,一刷新就是Cannot GET xxx ,就比如上面的例子,点击到page1,一刷新就是Cannot GET /page1.
路由使用
引入Vue-Router
案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js"></script>
<title>Vue Router</title>
</head>
<body>
<div id="app">
<ul>
<!-- 使用 router-link 组件来导航. -->
<!-- 通过传入 `to` 属性指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<router-link to="/page1">Go to Page1</router-link>
<br/>
<router-link to="/page2">Go to Page2</router-link>
</ul>
<!-- 路由出口 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
<script>
//定义路由组件,也可以从别的文件import进来
const Page1 = {
template: '<div>Page1</div>'
}
const Page2 = {
template: '<div>Page2</div>'
}
//定义路由
//每个路由需要映射一个组件,
//component也可以是Vue.extend()创建的组件构造器
//或者只是一个组件配置对象
const routes = [
{ path: '/page1',component: Page1 },
{ path: '/page2',component: Page2 }
]
//3.创建VueRouter实例
const router = new VueRouter({
routes:routes
})
//4.创建和挂载根实例
//通过router配置参数注入路由,从而让整个应用有路由功能
const app = new Vue({
router:router
}).$mount('#app')
</script>
</body>
</html>
运行后可以发现,地址栏有个#, VueRouter确实默认是hash模式
获取全局路由跳转参数的变化
<script>
...
//4.创建和挂载根实例
const app = new Vue({
router:router,
watch: {
$route(to, from) {
console.log('to',to);
console.log('from',from);
}
}
}).$mount('#app')
</script>
添加监听后,可以拿到to和from两个参数,to代表跳转后的页面参数,from代表你从哪个页面跳转来的,得到这两个参数,我们就可以设置一级二级页面,用来制作过场动画,也可以添加页面顶部的页面加载进度条。
获取路由中带的参数
路由传递参数有两种方法,分别是通过传递to和from中的query参数和params参数来实现的
通过传递参数:传递$route的query参数
给router-link标签添加参数
<router-link :to="{path:'/page1', query:{ id:111 }}">Go to Page1</router-link>
从下图看,to和from就是对应路由的$route
通过路由中带参数:传递$route的Params参数
route-link组件
<router-link to="/page2/222">Go to Page2</router-link>
定义路由组件
const Page2 = {
// 2.通过params
template: '<div>Page2 {{$route.params.id}}</div>'
}
定义路由
const routes = [
{ path: '/page1',component: Page1 },
// 2.通过params
{ path: '/page2/:id',component: Page2 }
]
可以看到修改了
重定向页面
当用户输入一个不存在的路由,Vue-Router无法匹配到的时候,需要默认回到首页,这就要用到重定向匹配,代码如下
const routes = [
{ path: '/page1', component: Page1 },
{ path: '/page2', component: Page2 },
{ path: '*', redirect: '/page1' }
]
这样当你输入了不存在的路由就会自动跳转到page1。
参考: