<!-- 1. 先在head中引用router.js -->
<div id="app">
<!-- 4.设置元素的显示 -->
<!-- to里面写的路径名与配置项中的路径名相同 -->
<!-- 这里的每一项相当于一个按钮,默认解析为a标签,可以通过tag属性进行修改 -->
<router-link to="/jay" tag="span">周杰伦</router-link>
<router-link to="/lili" tag="span">李雷</router-link>
<router-link to="/mike" tag="span">麦克</router-link>
<!-- 相当于一个占位符,标签里面不写内容,与插槽中的slot标签类似,相当于一个显示器 -->
<router-view></router-view>
</div>
<script>
// 2.路由配置项
// 先创建几个组件
let jay = {
template: `<div>周杰伦</div>`
}
let lili = {
template: `<div>李雷</div>`
}
let mike = {
template: `<div>麦克</div>`
}
// 配置路由的地址
let router = new VueRouter({
routes: [
{
path:"/jay", // 路径名可以自己定义,一般和组件名相同
component:jay // 填写组件名
},
{
path:"/lili",
component:lili
},
{
path:"/mike",
component:mike
}
],
mode:"hash" // 默认为hash 一般app使用hash 后台管理使用history
})
new Vue({
el: '#app',
router, // 3.将路由挂载在实例上,完整是 router:router ,但由于键值相同,可以只把键写出来
data() {
return {
}
},
methods: {
}
});
</script>
注意
{
path:"/",
redirect:"/组件名" // 重定向路径
}
这样就可以在打开页面时,显示我们想要默认显示的组件了。
name属性,这个属性对于路由的传参中会有一定的帮助一般我们在写app时用hash,在操作后台管理时用history比较多
路由传参有两种方式,一种是query,一种是params
/地址?id=1,要先写一个问号,然后在后面进行拼接,参数直接进入query中<router-link to="/lilei?id=3" tag="span">李雷</router-link>
我们想要获取拼接的内容时,在定义的组件中使用mounted钩子,就可以通过this.$route获取到此条路由上的参数,this.$route.query就能找到对应的query中的参数
let lilei={
template:`<div>李雷</div>`,
mounted() {
console.log(this.$router); // 打印整个路由
console.log(this.$route); // 打印路由的参数
console.log(this.$route.query); // {id: '3'}
},
}
/:参数名1/:参数名2的形式,将我们需要的参数进行设置,这里相当于函数中的一个形参,接着再router-link标签的to属性中进行拼接,/地址/参数1/参数2,这样就将参数传好了。 <router-link to="/hanmeimei/3/10" tag="span">韩梅梅</router-link>
-----------------------------------------------------------------------------
{
// 传参方式二 在path中设置要拼接什么参数,然后在router-link标签的to后面按顺序拼接
path:"/hanmeimei/:id/:key",
component:hanmeimei ,
name:"hanmeimei"
},
我们想要获取拼接的内容时,在定义的组件中使用mounted钩子,就可以通过this.$route获取到此条路由上的参数,this.$route.params就能找到对应的params中的参数
let hanmeimei = {
template:`<div>韩梅梅</div>`,
mounted() {
console.log(this.$router);
console.log(this.$route);
console.log(this.$route.params); // {id: '3', key: '10'}
},
}
除了使用router-link标签设置路由的点击项,我们还可以通过事件,对路由进行调用,而这个中也存在了传参的问题
我们先来看看如何使用事件触发路由,我们可以使用点击、按键按下、鼠标经过等事件,接下来举例会用到点击事件
<!-- 事件触发 -->
<button @click="cli('mike')">点击麦克</button>
cli(e){
this.$router.push({
name:e,
query:{
id:10,
key:20
},
params:{
name:99 // 刷新了就没有了
}
})
}
我们可以看到,这这里我就用到了之前提的name,但其实这里的name也不是必须的,如果我们只使用query传参,就可以不用写name,而是直接写path,将需要跳转的组件的地址写过来即可,这样就不必在配置路由规则时,给路由添加name属性了。但是我们在这里写了name之后,也就不用写path了,同样也能进行跳转,(注意:这里的name要和跳转的组件的name是相同的),我们要是想用params进行传参就一定要有name这个属性。但是params中的参数就类似是一次性的,在刷新以后就没有了。
路由嵌套呈现的效果就相当于,点击主页跳转到主页的组件,主页的组件中又包含了路由,点击主页组件中的元素,能够显示其他的组件
注意项:在配置嵌套组件设置path时,路径名前面不用加上“/”,在router-link标签的to属性中,要将父级的地址写在子级的前面/父级地址/子级地址。整个点击组件以及显示组件,都要放在父级的template中
<div id="app">
<router-link to="/mike">麦克</router-link>
<router-link to="/jack">杰克</router-link>
<router-link to="/ironMan">钢铁侠</router-link>
<router-view></router-view>
</div>
<script>
let mike = {
template: `<div>麦克</div>`
}
let jack = {
template: `<div>杰克</div>`
}
let spiderMan = {
template: `<div>蜘蛛侠</div>`
}
let arrowMan = {
template: `<div>绿箭侠</div>`
}
let beeMan = {
template: `<div>青蜂侠</div>`
}
let ironMan = {
// 嵌套的路由的地址前面,要加上父级组件的地址
template: `<div class="box"> <div>钢铁侠</div>
<router-link to="/ironMan/spiderMan">蜘蛛侠</router-link>
<router-link to="/ironMan/arrowMan">绿箭侠</router-link>
<router-link to="/ironMan/beeMan">青蜂侠</router-link>
<router-view></router-view>
</div>`
}
const router = new VueRouter({
routes: [
{
path: "/mike",
component: mike
},
{
path: "/jack",
component: jack
},
{
path: "/ironMan",
component: ironMan,
// 嵌套
children: [
{
path: "spiderMan",
component: spiderMan
},
{
path: "arrowMan",
component: arrowMan
},
{
path: "beeMan",
component: beeMan
},
]
}
]
})
new Vue({
el: '#app',
data() {
return {
}
},
methods: {
},
router,
});
</script>
使用路由的钩子函数,检测整个路由跳转的过程,可以在进入组件前或者进入组件后进行一些操作
路由守卫也有一定的分类:全局守卫、组件守卫、路由独享守卫。我们来看看它们都有哪些钩子函数
全局守卫
在全局进行使用
beforeEach 进入组件之前
afterEach 进入组件之后
router.beforeEach((to, from, next) => {
console.log(to,"全局to"); // 跳转到哪一个组件
console.log(from,"全局from"); // 从哪个组件跳转的
next() // next是一个回调函数,()里可以放地址,前往哪一个组件
})
需要注意的是,全局守卫要放在路由配置规则的后面,否则由于路由规则还未配置好,可能会报错
组件守卫
在各个组件中使用
beforeRouteEnter 进入组件前
afterRouteEnter 进入组件后
let mike = {
template: `<div>麦克</div>`,
beforeRouteEnter(to, from, next) {
console.log(to, "组件守卫的to");
next()
}
}
路由独享
在路由配置中使用
beforeEnter 进入组件前
afterEnter 进入组件后
let router = new VueRouter({
routes: [
{
path:"/lili",
component:lili,
// 路由独享
beforeEnter: (to, from, next) => {
console.log(to,"路由独享的to");
next();
}
},
],
})
我们可以看到,这些钩子都可以看到,页面跳转的一个过程:从哪个组件跳转(from),要跳转到哪一个组件(to)。其实这三类路由守卫,除了书写的地方不同,其他的作用以及参数都是相同的,而进入组件后的钩子用法是与进入组件前的钩子用法是相同的,而且相对来说进入组件后的钩子用的是很少的,所以就没有进行举例了,如果感兴趣可以自己试一试。
不过这几个钩子中有一个参数是要着重强调的:next,它是一个回调函数,()里填的是地址,表示前往哪一个组件,如果不填那么久跳转到默这条路由中默认的组件。这个回调函数很重要,如果使用了这些钩子,而不调用这个回调函数的话,那么组件是不会进行跳转的
对于路由守卫,我们有一个用法是用它来进行控制访问权限,这里有一段代码,它是用于模拟判断用户是否登录,如果登录就进行下一步操作,没有登录就跳转到登录组件
router.beforeEach((to, from, next) => {
if(sessionStorage.getItem("user")){ // 判断缓存中是否有用户信息
next() // 执行下一步,如果没有next()就不会执行下一步了,很重要
}else{ // 以下是没有登录的情况
if(to.path==="/login"){
next() // 如果要去的组件是登录组件,就执行
}else{
next("/login") // 如果要去的组件不是登录组件,就强制去登录组件
}
}
})
另外我们还可以了解一下,从一个组件到另一个组件,我们要经历的钩子的顺序
除了使用以上的钩子来获取到从哪个组件跳转到哪个组件,我们还可以通过监听器来获取
watch: { // 通过监听,监听路由
"$route"(e, o) {
console.log(e.path); // 当前组件的地址
console.log(o.path); // 上一个组件的地址
}
}
今天讲的路由是很重要的,涉及到了怎么配置路由规则、怎么传参、怎么进行路由的嵌套以及路由守卫,我们了解到了很多的理论知识,但是如果缺乏实践、案例的支持,我们对路由的了解是很少的,希望在接下来的项目中,不断夯实自己对于路由的理解,到时一定会再来对这篇文章进行修改的。
接下来,针对于今天所学,我进行了一个总体的运用:从配置路由到传参、嵌套、守卫进行一个融合,放在一个案例中。上面的理论融合了很多自己的理解,可能会不太对,但是案例是没毛病的,如果有的话那就得改了
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>路由总体</title>
<script src="./js/vue.min.js"></script>
<script src="./js/vue-router.js"></script>
<!-- 1.先引入路由的js文件 -->
<style>
.tip {
display: inline-block;
width: 200px;
line-height: 30px;
text-align: center;
cursor: pointer;
}
.box {
background-color: #0ff;
color: rgb(250, 243, 243);
padding: 50px;
width: fit-content;
}
</style>
</head>
<body>
<div id="app">
<!-- 4. 控制显示 -->
<router-link to="/cat/20/30" tag="span" class="tip">小猫</router-link>
<router-link to="/dog" tag="span" class="tip">小狗</router-link>
<!-- 第一种传参方式,query 直接在router-link标签的to属性中拼接 ?参数名=参数 -->
<router-link to="/tiger?id=20" tag="span" class="tip">老虎</router-link>
<router-link to="/morea" tag="span" class="tip">更多</router-link>
<router-view></router-view>
<!-- 事件控制路由 -->
<!-- 暂时只能点击一次,点多了会报错 -->
<button @click="dogShow">点击到小狗</button>
</div>
<script>
// 2.配置路由
let cat = {
template: `<div class="box">小猫</div>`,
mounted() {
console.log(this.$route, "小猫");
},
beforeRouteEnter(to, from, next) {
console.log(to, "这是组件守卫中的to"); // 跳转到哪一个组件
console.log(from, "这是组件守卫中的from"); // 从哪一个组件跳转来
next() // 执行下一步
}
}
let dog = {
template: `<div class="box">小狗</div>`,
mounted() {
console.log(this.$route, "小狗");
},
beforeRouteEnter(to, from, next) {
console.log(to, "这是组件守卫中的to"); // 跳转到哪一个组件
console.log(from, "这是组件守卫中的from"); // 从哪一个组件跳转来
next() // 执行下一步
}
}
let tiger = {
template: `<div class="box">老虎</div>`,
beforeRouteEnter(to, from, next) {
console.log(to, "这是组件守卫中的to"); // 跳转到哪一个组件
console.log(from, "这是组件守卫中的from"); // 从哪一个组件跳转来
next() // 执行下一步
}
}
let morea = {
template: `<div class="box"><div>更多</div>
<router-link to="/morea/bird" tag="span">小鸟</router-link>
<router-link to="/morea/snake" tag="span">大蟒蛇</router-link>
<router-link to="/morea/chicken" tag="span">大公鸡</router-link>
<router-view></router-view>
</div>`
}
let bird = {
template: `<div>小鸟</div>`
}
let snake = {
template: `<div>大蟒蛇</div>`
}
let chicken = {
template: `<div>大公鸡</div>`
}
const router = new VueRouter({
routes: [
{
path: "/",
redirect: "/morea" // 默认显示更多
},
{
// 第二种传参方式,在路由配置中的path中进行拼接,将参数名拼接在这里,将参数值拼接在router-link标签的to属性中
path: "/cat/:key/:id",
component: cat,
name: 'cat',
beforeEnter: (to, from, next) => {
console.log(to,"这是路由独享中的to")
console.log(from,"这是路由独享中的from");
next() // 执行下一步
}
},
{
path: "/dog",
component: dog,
name: "dog",
beforeEnter: (to, from, next) => {
console.log(to,"这是路由独享中的to")
console.log(from,"这是路由独享中的from");
next() // 执行下一步
}
},
{
path: "/tiger",
component: tiger,
name: "tiger",
beforeEnter: (to, from, next) => {
console.log(to,"这是路由独享中的to")
console.log(from,"这是路由独享中的from");
next() // 执行下一步
}
},
{
path: "/morea",
component: morea,
name: "morea",
// 路由嵌套
children: [
{
path: "/morea",
redirect: "bird" // 设置默认显示
},
{
path: "bird",
component: bird
},
{
path: "snake",
component: snake
},
{
path: "chicken",
component: chicken
}
]
}
]
})
// 全局路由守卫
router.beforeEach((to, from, next) => {
console.log(to, "这是全局守卫的to"); // 到哪个组件
console.log(from, "这是全局守卫的from"); // 从哪个组件来
next() // 执行下一步
})
new Vue({
el: '#app',
data() {
return {
}
},
methods: {
dogShow() {
this.$router.push({
name: "dog",
query: { // 通过query传递参数,在url中拼接
id: 15
},
params: {
key: 50 // 相当于一个临时储存,刷新以后就会清空
}
})
}
},
// 3.挂载路由
router,
watch: { // 通过监听,监听路由
"$route"(e, o) {
console.log(e.path); // 当前组件的地址
console.log(o.path); // 上一个组件的地址
}
}
});
</script>
</body>
</html>