目录
路由机制
vue-router是vue的一个插件,用来提供路由功能。通过路由的改变可以动态加载组件,达到开发单页面程序的目的。
安装
方式一 : CDN引入
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/vue-router/3.6.5/vue-router.js"></script>
方式二:本地引入
<script src='vue.js'></script>
<script src='vue-router.js'></script>
方式三 : cnpm下载
cnpm install vue-router
使用
在html文件中使用时需要引入vueRouter(先引入vue.js,在引入vueRouter)
<script>
// 声明组件
let myA = {
template: `
<div>A组件</div>
`
};
let myB = {
template: `
<div>B组件</div>
`
};
// 1.定义路由对象数组 route路由对象 router路由器对象 routes路由对象组
let routes = [{
path: '/a',
component: myA
}, {
path: '/b',
component: myB
}];
// 2.创建路由器对象 声明路由器实例对象
let router = new VueRouter({
// 声明配置路由对象
routes: routes
})
// 3.注册路由器对象
new Vue({
el: '#app',
// 将路由实例对象导入vue实例,相当于router:router,在此使用简写形式
router,
components: {
'my-a': myA,
'my-b': myB
},
data: {
msg: 'hello'
},
})
</script>
<div id="app">
{{msg}}
<!-- 4.实现路由切换,router-link的本质是创建a标签 -->
<div>
<router-link to="/a">去A路由</router-link>
<router-link to="/b">去B路由</router-link>
<a href="#/a">a标签路由去A</a>
</div>
<div>
<!-- 路由组件显示的位置 路由出口,将匹配到的路由组件,渲染到此-->
<router-view></router-view>
</div>
</div>
let routes=[
{
path:"/",
//路由名称
name:"aRoute",
//别名 重命名
alias:'/aa',
//重定向
// redirect:'/a'
redirect:{name:'aRoute'}
}
]
动态路由匹配
需要把某种模式匹配到的所有路由,全部映射到同一个组件。
例如 : 有一个user组件,对于所有id不同的用户,都要使用这个组件来渲染,那么可以在vue-router的路由路径中使用动态路径参数来达到这个效果。
复用组件时,想对路由参数的变化作出响应的话,你可以简单地 watch $route 对象,或者使用组件内部的导航守卫
<div id="app">
{{msg}}
<!-- 4.使用路由 -->
<div>
<router-link to="/user/id/1/username/zhangsan">去A路由</router-link>
</div>
<div>
<!-- 路由组件显示的位置 -->
<router-view></router-view>
</div>
</div>
// 声明组件
<script>
let myA = {
data() {
return {
id: null,
username: ''
}
},
template: `
<div>A组件{{id}}--{{username}}</div>
`,
/* created() {
alert(1);
// console.log(this.$route);
this.id = this.$route.params.id;
this.username = this.$route.params.username;
} */
//监听
/* watch: {
msg(newValue, oldValue) { },
$route:{
handler(){
// to是新路由 from是旧路由
// console.log(to, from);
this.id = this.$route.params.id;
this.username = this.$route.params.username;
},
deep:true
}
} */
// 监听路由发生变化 路由守卫
beforeRouteUpdate(to, from, next) {
// console.log(to.params);
this.id = to.params.id;
this.username = to.params.username;
// 继续
// next();
// 阻断
// next(false)
}
};
let myB = {
template: `
<div>B组件</div>
`
};
// 1.定义路由对象数组 route路由对象 router路由器对象 routes路由对象组
let routes = [{
// 动态路由
// /user/id/1/username/zhangsan
// /user/id/2/username/lisi
path: '/user/id/:id/username/:username',
component: myA
}];
// 2.创建路由器对象
let router = new VueRouter({
routes: routes
})
// 3.注册路由器对象
new Vue({
el: '#app',
router: router,
components: {
'my-a': myA,
'my-b': myB
},
data: {
msg: 'hello'
},
methods: {}
})
</script>
嵌套路由
实际生活中的应用界面,通常由多层嵌套的组件组合而成。同样地,URL 中各段动态路径也按某种结构对应嵌套的各层组件 :
<body>
<div id="app">
<router-link to='user'>去用户</router-link>
<router-link to='manager'>去管理员</router-link>
<router-view></router-view>
</div>
</body>
<script>
// 创建一个组件
let user = {
template: `
<div>
<router-link to='/userChild1'>子组件1</router-link>
<router-link to='/userChild2'>子组件2</router-link>
<router-view ></router-view>
</div>
`
}
let manager = {
template: `
<div>管理员</div>
`
}
let userChild1 = {
template: `
<div>子组件1</div>
`
}
let userChild2 = {
template: `
<div>子组件2</div>
`
}
let routes = [{
path: '/manager',
component: manager
}, {
path: '/user',
component: user,
redirect: '/userChild1',
children: [{
path: "/userChild1",
component: userChild1
}, {
path: "/userChild2",
component: userChild2
}]
}];
let router = new VueRouter({
routes
})
new Vue({
el: "#app",
router,
data: {
}
})
编程式导航
除了使用
<router-link>
创建 a 标签来定义导航链接,还可以借助 router 的实例方法,通过编写代码来实现。this.$router.push()跳转到指定路由,会向history栈添加一个新的记录,当用户点击浏览器回退按钮的时候,可以回到跳转前的url。
<script>
// 创建A B组件
let myA = {
data() {
return {
}
},
template: `
<div>
A组件
</div>
`,
created() {
console.log(this.$route)
},
}
let myB = {
data() {
return {
}
},
template: `
<div>
B组件
</div>
`
};
// 创建路由组件对象数组 routes router路由器对象 route路由对象
let routes = [
{
path: "/a",
component: myA,
name: 'mya'
},
{
path: "/b",
component: myB,
}
];
// 创建路由器对象实例
let router = new VueRouter({
// 配置路由对象组
routes
})
new Vue({
el: '#app',
data: {
},
// 3.注册路由
router,
components: {
'my-a': myA,
'my-b': myB
},
methods: {
toPath() {
this.$router.push({
path: "/a",
// 有效
// query:{id:1},
})
},
toPath1() {
this.$router.push({
name: 'mya',
query: { id: 1 },
// 参数是一次性携带刷新页面 params失效
params: {
name: "terry"
}
}),
// this.$router.replace({
// path:"/column",
// query:{id:1}
// })
}
}
})
</script>
<div id="app">
<router-link to='/a'>去a路由</router-link>
<router-link to='/b'>去b路由</router-link>
<a href="#/a/2">去a路由</a>
<button @click="$router.push('/a')">跳转到A路由</button>
<button @click="$router.push('a')">跳转到A2路由</button>
<button @click="toPath">跳转到A3路由</button>
<button @click="toPath1">跳转到A4路由</button>
<router-view></router-view>
</div>
//跳转到指定页面 可传递参数 前进一步记录 router.go(1) // 后退一步记录,等同于 history.back() router.go(-1) // 前进 3 步记录 router.go(3) // 如果 history 记录不够用,则会报错 router.go(-100) router.go(100)
路由组件传参
路由传递是指,从A页面跳转到B页面时,将A页面中的变量传递给B页面使用,传递参数的方式有两种 :
path-query传参
使用path与query结合的方式传递参数时,参数会被拼接在浏览器地址栏中,并且刷新页面后数据也不会丢失。
name-params传参
path-query传参
<script>
let user = {
template: `
<div @click="userHandler">普通用户,点击此处可跳转至管理员页面</div>
`,
data() {
return {
list: "hello",
obj: {
name: 'tom',
age: 3
}
}
},
methods: {
userHandler() {
// 跳转
this.$router.push({
path: '/manager',
query: {
list: this.list,
obj: JSON.stringify(this.obj)
}
})
}
},
}
let manager = {
template: `
<div>管理员 {{$route.query.list}} {{$route.query.obj}}</div>
`
}
let router = new VueRouter({
routes: [{
path: '/user',
component: user
}, {
path: '/manager',
component: manager
}]
})
new Vue({
el: "#app",
router
})
</script>
<div id="app">
<router-link to="/user">user</router-link>
<router-link to="/manager">manager</router-link>
<router-view></router-view>
</div>
name-params传参
<script>
let user = {
template: `
<div @click="userHandler">普通用户,点击此处可跳转至管理员页面</div>
`,
data() {
return {
list: "hello",
obj: {
name: 'tom',
age: 3
}
}
},
methods: {
userHandler() {
// 跳转
this.$router.push({
name: 'manager',
params: {
list: this.list,
obj: JSON.stringify(this.obj)
}
})
}
},
}
let manager = {
template: `
<div>管理员 {{$route.params.list}} {{$route.params.obj}}</div>
`
}
let router = new VueRouter({
routes: [{
path: '/user',
component: user,
name: 'user'
}, {
path: '/manager',
component: manager,
name: 'manager'
}]
})
new Vue({
el: "#app",
router
})
</script>
<div id="app">
<router-link to="/user">user</router-link>
<router-link to="/manager">manager</router-link>
<router-view></router-view>
</div>
路由模式
hash模式
hash模式的工作原理是hashchange事件,可以在window监听hash的变化。我们在url后面随便添加一个#xx触发这个事件。
window.onhashchange = function(event){ console.log(event); // 打印出一个HashChangeEvent事件对象,在该对象内有newURL和oldURL // location.hash中也有相关的信息 // 假设hash值是个颜色值,通过location.hash来获取到对应的hash值,然后设置页面中的某个元素的背景颜色来改变页面 }
history模式
把window.history对象打印出来可以看到里边提供的方法和记录长度 history对象内有back(),forword(),go()等方法 前进,后退,跳转操作方法:
history.go(-3);//后退3次 history.go(2);//前进2次 history.go(0);//刷新当前页面 history.back(); //后退 history.forward(); //前进
vue-router使用的模式
vue-router 默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。如果不想要很丑的 hash,可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。不过这种模式要玩好,还需要后台配置支持。
hash路由和history路由的区别:
1.hash路由在地址栏URL上有#,而history路由没有会好看一点
2.进行回车刷新操作,hash路由会加载到地址栏对应的页面,而history路由一般就404报错了(刷新是网络请求,没有后端准备时会报错)。
3.hash路由支持低版本的浏览器,而history路由是HTML5新增的API。
4.hash的特点在于它虽然出现在了URL中,但是不包括在http请求中,所以对于后端是没有一点影响的,所以改变hash不会重新加载页面,所以这也是单页面应用的必备。
5.history运用了浏览器的历史记录栈,之前有back,forward,go方法,之后在HTML5中新增了pushState()和replaceState()方法(需要特定浏览器的支持),它们提供了对历史记录进行修改的功能,不过在进行修改时,虽然改变了当前的URL,但是浏览器不会马上向后端发送请求。
导航守卫 --路由的改变会触发导航守卫
全局守卫
全局守卫有全局前置守卫、全局后置守卫。
const router = new VueRouter({ ... }) router.beforeEach((to, from, next) => { // ... })
const router = new VueRouter({ ... }) router.afterEach((to, from) => { // ... })
路由独享守卫
组件内守卫
beforeRouteEnter: (to, from, next) => { //不!能!获取组件实例
this
} beforeRouteUpdate (to, from, next) {//在当前路由改变,但是该组件被复用时调用,可访问this} beforeRouteLeave (to, from, next) {//导航离开该组件的对应路由时调用,可访问this}
全局前置守卫
let router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
全局后置钩子
let router = new VueRouter({ ... })
router.afterEach((to, from) => {
// ...
})
全局守卫参数说明:
* to: Route : 即将要进入的目标路有对象
* from: Route : 当前导航正要离开的路由
* next: Function : 一定要调用该方法来**resolve**这个钩子。执行效果依赖 next 方法的调用参数
路由独享守卫
可以在路由配置上直接定义 beforeEnter 守卫,改守卫与全局前置守卫的方法参数是一样的 :
let router = new VueRouter({
routes: [
{
path: '/home',
component: Home,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
组件内的守卫
beforeRouteEnter(to,from,next){
// this--window
console.log(this,'beforeRouteEnter');
next()
},
beforeRouteUpdate(to,from,next){
//this--组件实例
console.log(this,'beforeRouteUpdate');
next()
},
beforeRouteLeave(to,from,next){
//this--组件实例
console.log(this,'beforERouteLeave')
}