This is a Lengux blog.

We sat and drank with the sun on our shoulders and felt like free men. We could have been tarring the roof of one of our own houses. We were the lords of all creation. As for Andy,he spent that break hunkered in the shade,a strange little smile on his face,watching us drink his beer.

vue-router

vue-router 路由

一个路由(route)就是一组映射关系(key - value),多个路由需要路由器(router)进行管理。

前端路由:key是路径,value是组件。

入门组件

router-link组件

使用 router-link 组件进行导航
通过传递 to 来指定链接
将呈现一个带有正确href属性的 a标签

tag=”span”

设置路由渲染标签(也就是呈现出来的标签) 已废弃不建议使用

exact-active-classactive-class

设置路由标签选中时的样式,也就是说当网页路由和路由标签同步时,会添加一个_active类名(可以写入css样式)

1
2
3
4
5
6
7
8
._active{
background-color : red;
}

//此方法采用模糊匹配,也就是只要路径包含路由就会激活
active-class = "_active"
//此方法采用严格匹配,也就是只有当路径和配置路径严格相同时才会激活
exact-active-class = "_active"
router-link自定义导航
1
2
3
4
5
6
7
8
9
<router-link custom  v-slot="{ href, route, navigate, isActive, isExactActive }
//
custom:用户自定导航
v-slot:解构获取组件内的传值
href 路由地址
route路由对象
navigate 跳转函数
isActive 导航激活状态 true 或fasle
isExactActive 子导航激活状态 true 或 false

router-link 的replace属性

  1. 作用:控制路由跳转时操作浏览器历史记录的模式
  2. 浏览器的历史记录有两种写入方式:分别为pushreplacepush是追加历史记录,replace是替换当前记录。路由跳转时候默认为push
  3. 如何开启replace模式:News
router-view组件

路由的出口,在配置文件里匹配到的组件将通过view标签渲染

router路由文件配置

分析文件默认配置

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
// 1. 定义路由组件.
// 也可以从其他文件导入
const Home = { template: '<div>Home</div>' }
const About = { template: '<div>About</div>' }

// 2. 定义一些路由
// 每个路由都需要映射到一个组件。
// 我们后面再讨论嵌套路由。
const routes = [
{ path: '/', component: Home },
{ path: '/about', component: About },
]

// 3. 创建路由实例并传递 `routes` 配置
// 你可以在这里输入更多的配置,但我们在这里
// 暂时保持简单
const router = VueRouter.createRouter({
// 4. 内部提供了 history 模式的实现。为了简单起见,我们在这里使用 hash 模式。
history: VueRouter.createWebHashHistory(),
routes, // `routes: routes` 的缩写
})

// 5. 创建并挂载根实例
const app = Vue.createApp({})
//确保 _use_ 路由实例使
//整个应用支持路由。
app.use(router)

app.mount('#app')

// 现在,应用已经启动了!

命名路由和路径路由

一般情况下link的to属性接收字符串路径,但是vue的内置指令:,加在to上时,那么:to=’’的值将会被当作表达式解析,当路由嵌套过多,避免拼写错误,我们有时会使用name来写入路由名字,通过:to解析表达式来使用。

1
2
3
4
5
6
7
const routes = [
{
path: '/user/:username',
name: 'user',
component: User,
},
]

这样写能使用name选择路由,还能传递插槽值,和调用$router.push是一回事

1
2
3
<router-link :to="{ name: 'user', params: { username: 'erina' }}">
User
</router-link>

还可以传递query参数

1
2
3
<router-link :to="{ path:'/register', query: { plan: 'private' } }">
User
</router-link>

路由传值

很多时候,我们需要给很多的不一样的用户匹配到同一个组件路由,但是我们不能让每个用户的页面一样,那么为了实现不同用户匹配不同页面,我们使用了动态路由的方式(路径参数)

那么,我们应该怎么拿到传入的参数呢,已知插件绑定到vue根实例上时,所有的插件的Api都可以在原型链上找到,vue设置了这样一个Api (this.$route)

这样的话所有的组件通过this.$route都可以访问到原型链上的route

插槽传值

1
2
3
4
{ path: '/users/:id', component: User },
//当我们这样配置路径时,那么users/jkjk和users/okoko的映射页面是一样的,但是后面的值会被传入
<router-link to="/jhjhjh">24242</router-link>
//通过$route.params拿到值 {id:jhjhjh}
匹配模式 匹配路径 $route.params
/users/:username /users/eduardo { username: 'eduardo' }
/users/:username/posts/:postId /users/eduardo/posts/123 { username: 'eduardo', postId: '123' }

哈希传值

1
2
3
//不需要配置路径插槽,直接哈希传值
<router-link to="/?a=11">24242</router-link>
//通过$route.query拿到值 {a:11}

路由props传值配置

props的第一种写法值为对象,该对象的所有key-value都会以props的形式传给组件(死数据)

1
2
3
4
5
6
7
8
9
10
//路由中配置参数
{
path: 'detail/:id/:title',
props:{
a:1,
b:'hello'
}
}
//组件内接收
props: ['id', 'title']

props的第二种写法,值为布尔值,布尔值为真,就会把该路由组件收到的所有params参数以props的形式传递给组件(此方法不会传递query参数)

1
2
3
4
5
//路由中配置参数
{
path: 'detail/:id/:title',
props: true
}

props的第三种写法,值为函数

1
2
3
4
5
6
7
8
9
10
//路由中配置参数
{
path: 'detail/:id/:title',
props({ query , params }){
return {
query.id,
params.title
}
}
}

嵌套子集路由

子集路由使用children来配置

children 配置只是另一个路由数组,就像 routes 本身一样。因此,你可以根据自己的需要,不断地嵌套视图。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const routes = [
{
path: '/user/:id',
component: User,
children: [
{
// 当 /user/:id/profile 匹配成功
// UserProfile 将被渲染到 User 的 <router-view> 内部
path: 'profile',
component: UserProfile,
},
{
// 当 /user/:id/posts 匹配成功
// UserPosts 将被渲染到 User 的 <router-view> 内部
path: 'posts',
component: UserPosts,
},
],
},
]

当你的一级路由下如果想要不跳转其他路由但是渲染其他路由的东西时,可以提供一个空路径

1
2
3
4
5
6
7
8
9
10
11
const routes = [
{
path: '/user/:id',
component: User,
children: [
// 当 /user/:id 匹配成功
// UserHome 将被渲染到 User 的 <router-view> 内部
{ path: '', component: UserHome },
],
},
]

编程式导航

注意:在 Vue 实例中,你可以通过 $router 访问路由实例。因此你可以调用 this.$router.push

想要导航到不同的 URL,可以使用 router.push 方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,会回到之前的 URL。

当你点击 <router-link> 时,内部会调用这个方法,所以点击 <router-link :to="..."> 相当于调用 router.push(...)

参数

注意:当通过params传递数据时,不能设置path路径(要使用name名称),方便vue底层辩别路径与数据

1
2
3
4
5
6
7
8
9
10
11
// 字符串路径
this.$router.push('/users/eduardo')

// 带有路径的对象
this.$router.push({ path: '/users/eduardo' })

// 命名的路由,并加上参数,让路由建立 url
this.$router.push({ name: 'user', params: { username: 'eduardo' } })

// 带查询参数,结果是 /register?plan=private
this.$router.push({ path: '/register', query: { plan: 'private' } })
replace

需要注意的是除了push方法外,还有replace方法,也是跳转路径的方法

它的作用类似于 router.push,唯一不同的是,它在导航时不会向 history 添加新记录,正如它的名字所暗示的那样——它取代了当前的条目。

1
2
3
this.$router.push({ path: '/home', replace: true })
// 相当于
this.$router.replace({ path: '/home' })
前进后退
1
2
3
4
5
6
7
8
9
this.$router.forward() //前进
this.$router.back() //后退
this.$router.go() //可前进也可后退 参数是number类型(正数为前进的步数,负数为后退的部署)

this.$router.go(1) // 向前移动一条记录,与 router.forward() 相同

this.$router.go(-1) // 返回一条记录,与 router.back() 相同

this.$router.go(-100) // 如果没有那么多记录,静默失败

他的很多Api都是模仿的windoe.History原生的方法,可以直接使用原生方法

编程式导航的实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<ul>
<li> <span @click="go({ name: 'home', query: { age: 18 } })">首页</span> </li>
<li> <span @click="go({ name: 'list', params: {id:1111,name:'zhangsan'} })">列表</span></li>
</ul>

go(href) {
// 字符串的方式
// /home?age=18
// /list/123/aaa/zhangsan
this.$router.push(href); // history.pushstate
this.$router.push(href).catch((err) => { }); //location.href=''
// 对象形式的
// { name: 'home', query: { age: 18 } }
// { name: 'list', params: {id:1111,name:'zhangsan'} }
}

命名视图

有时候想同时 (同级) 展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar (侧导航) 和 main (主内容) 两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view 没有设置名字,那么默认为 default

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<router-view name="LeftSidebar"></router-view>
<router-view></router-view>
<router-view name="RightSidebar"></router-view>

const router = createRouter({
history: createWebHashHistory(),
routes: [
{
path: '/',
components: {
default: Home,
// LeftSidebar: LeftSidebar 的缩写
LeftSidebar,
// 它们与 `<router-view>` 上的 `name` 属性匹配
RightSidebar,
},
},
],
})

重定向

重定向通过对rouder的配置来完成

1
2
3
4
5
6
7
8
9
10
11
12
13
const routes = [{ path: '*', redirect: '/home' }]
//意思就是什么都匹配不到的时匹配到/home路由上
const routes = [{ path: '/home', redirect: { name: 'homepage' } }]
//意思就是匹配到/home时,重定向到一个name叫homepage的路由上

{
path: '/search/:searchText',
redirect: to => {
// 方法接收目标路由作为参数
// return 重定向的字符串路径/路径对象
return { path: '/search', query: { q: to.params.searchText } }
},
},

路由组件生命周期钩子

作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。

具体名字:

  • activated路由组件被激活时触发。
  • deactivated路由组件失活时触发。

路由元信息

通过绑定路由元信息,可以为每个路由设置特殊的属性

1
2
3
4
5
{
path: '/bar',
component: Bar,
meta: { isAuth: true }
}

首先,我们称呼 routes 配置中的每个路由对象为 路由记录。路由记录可以是嵌套的,因此,当一个路由匹配成功后,他可能匹配多个路由记录

一个路由匹配到的所有路由记录会暴露为 $route 对象 (还有在导航守卫中的路由对象) 的 $route.matched 对象。

路由守卫

作用:对路由进行权限控制

分类:全局守卫、独享守卫、组件内守卫

全局守卫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//全局前置守卫:初始化时执行、每次路由切换前执行
router.beforeEach((to,from,next)=>{
if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
if(localStorage.getItem('school') === 'yunheshuju'){ //权限控制的具体规则
next() //放行
}else{
alert('暂无权限查看')
}
}else{
next() //放行
}
})

//全局后置守卫:初始化时执行、每次路由切换后执行
router.afterEach((to,from)=>{
if(to.meta.title){
document.title = to.meta.title //修改网页的title
}else{
document.title = 'vue_test'
}
})

局部首位

1
2
3
4
5
6
7
8
9
10
11
12
beforeEnter(to,from,next){
console.log('beforeEnter',to,from)
if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
if(localStorage.getItem('school') === 'yunheshuju'){
next()
}else{
alert('暂无权限查看')
}
}else{
next()
}
}

组件内首位

1
2
3
4
5
6
//进入守卫:通过路由规则,进入该组件时被调用
beforeRouteEnter (to, from, next) {
},
//离开守卫:通过路由规则,离开该组件时被调用
beforeRouteLeave (to, from, next) {
}

缓存路由组件

1
2
3
4
5
6
7
8
9
10
11
12
13
<keep-alive>
//当入口标签被keep-alive包裹时,入口组件引用的组件全部会被缓存,这样会导致很多多余的东西也被缓存,造成负担较大,而且效果不好
<router-view />
</keep-alive>


<keep-alive include="News">
//include属性指定缓存组件(使用组件name名,而不是路由name)
<router-view />
</keep-alive>

//include属性数组写法(可以写入多个指定缓存组件)
include=["News"]

路由器的两种工作模式

对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值。

hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器。

hash模式:

  1. 地址中永远带着#号,不美观 。
  2. 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
  3. 兼容性较好。

history模式:

  1. 地址干净,美观 。
  2. 兼容性和hash模式相比略差。
  3. 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。

路由分类

  • 后端路由:

value 是 function, 用于处理客户端提交的请求。

工作过程:服务器接收到一个请求时, 根据请求路径找到匹配的函数 来处理请求, 返回响应数据。

  • 前端路由:

value 是 component,用于展示页面内容

工作过程:当浏览器的路径改变时, 对应的组件就会显示

user@ui-verse:~$
Hey!

In the sea of coding, I am Lengux, pursuing creativity and user experience.

 友情链接
 标签
Made with 💛 by Lengux and some fantastic contributors! hexo blog framework
豫ICP备2022014432号-1