那这次呢?我决定直接就先放一个小小demo上来
<body>
<div id="app">
<router-link to="/user">user</router-link>
<router-link to="/about">about</router-link>
<!-- 匹配到的路由组件都放在这里 -->
<router-view></router-view>
</div>
<script src="../lib/vue.js"></script>
<script src="../lib/vue-router.js"></script>
<script>
//定义组件模板
const User = { template: '<h1>user</h1>' }
const About = { template: '<h1>about</h1>' }
// 定义路由配置
const routes = [
{ path: "/user", component: User },
{ path: "/about", component: About },
]
// 初始化路由
const router = new VueRouter({
routes
})
// 使用路由
new Vue({
router
,mounted() {
// 访问路由器也就是VueRouter实例
console.log(this.$router);
// 访问当前的路由信息
console.log(this.$route);
},
}).$mount("#app");
</script>
</body>
其实我们在引入vue-router插件那一刻,我们的网页就已经附带上hash路由了,哪怕什么都没有做
那么你打开这个demo就会发现url最后加上了#/hash路由的标记了,然后我们通过router-lInk
标签跳转路由(其实a标签也行,但是a标签必须要写出相对完整的URL)这样一个简单的vue-router就实现了
路由传参
params传参
<router-link to="/user/小钢炮">小钢炮</router-link>
<router-link to="/user/大钢炮">大钢炮</router-link>
<!-- 如果未匹配到params参数就为空 -->
<router-link to="/user">我是哪个</router-link>
//打印接收到的参数
const User = { template: '<h1>{{this.$route.params.id}}</h1>' }
// 定义路由配置
const routes = [
// 通过:属性名的方式指定接收参数的名字
{ path: "/user/:id", component: User },
]
path匹配url可以使用正则
<router-link to="/user-小钢炮">小钢炮</router-link>
<router-link to="/user-大钢炮">大钢炮</router-link>
<!-- 如果未匹配到params参数就为空 -->
<router-link to="/user-">我是哪个</router-link>
//使用通配符,组件中会有一个params对象中有一个pathMatch值,代表通配符匹配到的内容
const User = { template: '<h1>我匹配到了 {{$route.params.pathMatch}}</h1>' }
const routes = [
// 匹配所有user-开头的路由
{ path: "/user-*", component: User },
// 所以我这里就可以匹配所有的路由,但是这个匹配规则必须放在最后面
// 因为vue-router是从前到后一次匹配的,这个可以做一个默认的无匹配路由的404组件
// {path:"*",component:main}
]
嵌套路由
<body>
<div id="app">
<!-- 我这里定义了一个跳转层级的标签 -->
<router-link to="/user">user界面</router-link>
<!-- 匹配到的路由组件都放在这里 -->
<router-view></router-view>
</div>
<template id="user">
<div>
<h1>user组件</h1>
<router-link to="/user/大钢炮">大钢炮</router-link>
<!-- 每一个组件中还有子路由必须要加router-view组件 -->
<router-view></router-view>
</div>
</template>
<template id="DaPao">
<div>
<h2>大钢炮</h2>
<router-link to="/user/大钢炮/小钢炮">小钢炮</router-link>
<!-- 每一个组件中还有子路由必须要加router-view组件 -->
<router-view></router-view>
</div>
</template>
<template id="XiaoPao">
<div>
<h3>我是大钢炮的儿子小钢炮 --->> 8888</h3>
</div>
</template>
<script src="../lib/vue.js"></script>
<script src="../lib/vue-router.js"></script>
<script>
const User = { template: "#user" }
const DaPao = { template: "#DaPao" }
const XiaoPao = { template: "#XiaoPao" }
const routes = [
{
path: "/user", component: User,
// 每一个匹配规则都有一个children属性,就跟routes一样的配置,里面配置对应规则中的子路由
children: [
// 不要写 / ,不然就是匹配跟路由了,vue会自动转换为/user/大钢炮的
{
path: "大钢炮", component: DaPao,
// 理论上来说是可以无限嵌套的
children: [
{ path: "小钢炮", component: XiaoPao }
]
}
]
},
]
// 初始化路由
const router = new VueRouter({
routes
})
// 使用路由
new Vue({
router
}).$mount("#app");
</script>
</body>
<body>
<div id="app">
<!-- 我这里定义了一个跳转层级的标签 -->
<router-link to="/user/xiaoming">小明</router-link>
<router-link to="/user/xiaoming/xiaoming">真小明</router-link>
<!-- 匹配到的路由组件都放在这里 -->
<router-view></router-view>
</div>
<template id="user">
<div>
<h1>user组件</h1>
<router-link to="/user/大钢炮">大钢炮</router-link>
{{$route.params.id}}
<!-- 每一个组件中还有子路由必须要加router-view组件 -->
<router-view></router-view>
</div>
</template>
<template id="DaPao">
<div>
{{$route.params.id}}
</div>
</template>
<template id="XiaoPao">
<div>
<h3>我是大钢炮的儿子小钢炮 --->> 8888</h3>
</div>
</template>
<script src="../lib/vue.js"></script>
<script src="../lib/vue-router.js"></script>
<script>
const User = { template: "#user" }
const DaPao = { template: "#DaPao" }
const XiaoPao = { template: "#XiaoPao" }
const routes = [
{
// 这样的子路由匹配的啥呢
path: "/user/:id", component: User,
children: [
// 匹配的是/user/:id/xiaoming
{path:"xiaoming",component:DaPao},
// 如果希望/user/:id匹配到了想显示一些东西可以这样,path留空字符串
// /user/:id
{path:"",component:XiaoPao}
]
},
]
// 初始化路由
const router = new VueRouter({
routes
})
// 使用路由
new Vue({
router
}).$mount("#app");
</script>
</body>
编程式导航
除了使用
<router-link>
创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。
- router.push(location, onComplete?, onAbort?)
注意:在 Vue 实例内部,你可以通过 $router 访问路由实例。因此你可以调用 this.$router.push。当你点击 <router-link> 时,这个方法会在内部调用,所以说,点击 <router-link :to="..."> 等同于调用 router.push(...)。
// 字符串
router.push('home')
// 对象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
注意:如果提供了 path,params 会被忽略,上述例子中的 query 并不属于这种情况。取而代之的是下面例子的做法,你需要提供路由的 name 或手写完整的带有参数的 path:
const userId = '123'
router.push({ name: 'user', params: { userId }}) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123
// 这里的 params 不生效
router.push({ path: '/user', params: { userId }}) // -> /user
同样的规则也适用于 router-link 组件的 to 属性。
在 2.2.0+,可选的在 router.push 或 router.replace 中提供 onComplete 和 onAbort 回调作为第二个和第三个参数。这些回调将会在导航成功完成 (在所有的异步钩子被解析之后) 或终止 (导航到相同的路由、或在当前导航完成之前导航到另一个不同的路由) 的时候进行相应的调用。
注意: 如果目的地和当前路由相同,只有参数发生了改变 (比如从一个用户资料到另一个/users/1
->/users/2
),你需要使用 beforeRouteUpdate来响应这个变化 (比如抓取用户信息)。
- router.replace(location, onComplete?, onAbort?)
跟 router.push 很像,唯一的不同就是,它不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录。
- router.go(n)
这个方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步,类似
window.history.go(n)
.
// 在浏览器记录中前进一步,等同于 history.forward()
router.go(1)
// 后退一步记录,等同于 history.back()
router.go(-1)
// 前进 3 步记录
router.go(3)
// 如果 history 记录不够用,那就默默地失败呗
router.go(-100)
router.go(100)
你也许注意到
router.push
、router.replace
和router.go
跟window.history.pushState
、window.history.replaceState
和window.history.go
好像, 实际上它们确实是效仿window.history
API 的。
因此,如果你已经熟悉 Browser History APIs,那么在 Vue Router 中操作 history 就是超级简单的。
还有值得提及的,Vue Router 的导航方法 (push
、replace
、go
) 在各类路由模式 (history
、hash
和abstract
) 下表现一致。
命名路由
有时候,通过一个名称来标识一个路由显得更方便一些,特别是在链接一个路由,或者是执行一些跳转的时候。你可以在创建 Router 实例的时候,在 routes 配置中给某个路由设置名称。
const router = new VueRouter({
routes: [
{
path: '/user/:userId',
name: 'user',
component: User
}
]
})
要链接到一个命名路由,可以给 router-link 的 to 属性传一个对象:
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
这跟代码调用 router.push() 是一回事:
// params传参必须使用命名路由或者直接手写path
// path :"/user/"+this.msg --> `/user/${this.msg}`
router.push({ name: 'user', params: { userId: 123 }})
这两种方式都会把路由导航到 /user/123 路径。
命名视图
有时候想同时 (同级) 展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar (侧导航) 和 main (主内容) 两个视图,这个时候命名视图就派上用场了
<router-view name="nav"></router-view>
router-view
组件提供了一个name属性,根据name属性的不同允许同层级(同路由情况下)存在多个不同的组件,默认不加name的router-view
默认的name就是default
很想插槽的name
<!-- 每一个组件中还有子路由必须要加router-view组件 -->
<router-view name="DaPao"></router-view>
<router-view name="XiaoPao"></router-view>
<router-view></router-view>
const User = { template: "#user" }
const DaPao = { template: "#DaPao" }
const XiaoPao = { template: "#XiaoPao" }
const routes = [
{
path: "/",
// 同时显示多个组件使用components
components: {
default: User,
DaPao, XiaoPao
}
},
]
嵌套命名视图
<body>
<div id="app">
<router-link to="/user/about">关于</router-link>
<router-link to="/user/info">资料</router-link>
<!-- 默认router坑 -->
<router-view></router-view>
</div>
<script src="../lib/vue.js"></script>
<script src="../lib/vue-router.js"></script>
<script>
const About = {
template: `
<h3> \
About组件 \
</h3> \
`
}
const User = {
template: `
<h2> \
这是用户组件 \
<router-view></router-view>
<router-view name="profile"></router-view>
</h2> \
`
}
const Profile = {
template:`
<h1> \
Profile组件,嵌套视图组件 \
</h1> \
`
}
const Info = {
template:`
<h1> \
Info组件 \
</h1>
`
}
const routes = [
// 默认的根 / 会被重定向到/user路由下
{ path: "/", redirect: "/user" },
{
path: "/user", component: User, children: [
{path:"about",component:About},
// 嵌套视图组件
{path:"info",components:{
default:Info,
profile:Profile
}}
]
}
]
// 初始化路由
const router = new VueRouter({
routes
})
// 使用路由
new Vue({
router
}).$mount("#app");
</script>
</body>
重定向和别名
// 默认的根 / 会被重定向到/user路由下
{ path: "/", redirect: "/user" },
// 重定向也可以是一个对象
{ path: "/", redirect: {path:'/user'} },
//甚至是一个方法,动态返回重定向目标:
{ path: "/", redirect: to =>{
// to为一个目标路由信息
// return 重定向的 字符串路径/路径对象
return '/user'
} },
别名
声明了别名的路由,就像上面这个例子,你其实显示的是访问/you,其实里面还是渲染的/user的内容,虽然你访问的/you但是实际上返回的确实/user的内容
路由组件传参
在组件中使用 $route 会使之与其对应路由形成高度耦合,从而使组件只能在某些特定的 URL 上使用,限制了其灵活性。
const User = {
template: '<div>User {{ $route.params.id }}</div>'
}
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User }
]
})
const User = {
props: ['id'],
template: '<div>User {{ id }}</div>'
}
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User, props: true },
// 对于包含命名视图的路由,你必须分别为每个命名视图添加 `props` 选项:
{
path: '/user/:id',
components: { default: User, sidebar: Sidebar },
props: { default: true, sidebar: false }
}
]
})
props的几种类型
- 布尔类型
const routes = [
// props为bool值,为真代表会将params设置为组件的属性(根元素)
// 这里就是 ---> name === 匹配到的value
{ path: "/user/:name", component: User, props: true }
]
- 对象模式
const routes = [
// 如果props为对象,那么里面的键值对就会对应html元素中的属性进行设置
{ path: "/user/:name", component: User, props:{name:"suiyue"}}
]
- 函数模式
const routes = [
// 如果props为函数有一个可选的属性route,代表当前的路由信息
// 这样你便可以将参数转换成另一种类型,将静态值与基于路由的值结合等等。
{ path: "/user/:name", component: User, props:(route)=>({name:route.params.name})}
]
HTML5History模式
vue路由默认是hash模式,这种url感觉上不是那么的棒,所以vue可以使用html5支持的history模式,这种模式路由的URL更接近正常的URL,但是由于跟正常的URL很像所以每一个请求都将真实发出,所以服务端需要配置一个用于所有404的index.html页面,部分服务端配置例子
因为这样的话就会出现一种情况就是,页面不会出现404界面了,但是还记得之前说的通配符吗?我们可以直接将一个path匹配通配符的匹配规则放在最后面,这样的话就可以模拟出一个404界面了
进阶
导航守卫
说白了就是不同时期触发的钩子函数而已
- 全局前置守卫
// 全局前置守卫
router.beforeEach((to, from, next) => {
// to与from看下面
/*
next函数不仅可以通过调用继续路由
还可以改变路由的目标指向
next() --> 继续路由
next(false) --> 取消路由 | 也可以直接不调用
// 同样可以改变路由的指向,对象参数如router.push函数
next('/suiyue') or next({name:'user',params:{}})
next(error) --> (2.4+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。
*/
/*
一个坑
直接调用next()函数的回调地狱
当你直接调用next()函数重定向一个路由的时候
比如说
next('/user') 重定向到/user路由,那么这些钩子函数还会进行执行一次
就是加入这在这个钩子函数中使用了 next('/suiyue') 跳转到/suiyue路由
那么这个next函数一执行,立马又会重新执行钩子函数,所以又会重新进入这个函数
然后又执行到next('/suiyue')然后又进行执行,这样最后就会造成堆栈溢出错误了
大家可以直接在这个函数试试,所以next重定向路由的时候一定要进行一个判断
*/
})
- 全局解析守卫
在 2.5.0+ 你可以用
router.beforeResolve
注册一个全局守卫。这和router.beforeEach
类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。
// router就是vue-router实例
router.beforeResolve((to, from, next) => {
// 将要前往的路由
console.log(to);
// 从哪个路由跳转到这个路由
console.log(from);
setTimeout(()=>{
// 什么时候调用next什么时候继续解析路由
// 不调用将不会继续解析路由,相当于路由失败不会显示对应的组件
next();
},1000);
})
- 全局后置钩子
// 全局后置钩子
router.afterEach((to, from) => {
// 这两个参数跟全局解析守卫一样
// 如果前面有任何守卫(全局的或者局部的)没有调用next()将不会执行此钩子函数
console.log(to);
console.log(from);
})
守卫和钩子最大的不同在于,守卫有一个next回调函数,可以通过函数中的逻辑控制路由是否能够达到预期而选择是否继续路由,而钩子函数就不会影响路由本身,适合只用于处理逻辑
- 路由独享守卫
const routes = [
{
path: "/user/:name", component: User,
// 路由独享守卫
beforeEnter: (to, from, next) => {
next();
}
},
]
就记住了这么一句话,所有守卫就这么固定三个参数,所有钩子函数就没有next参数
- 组件内的守卫
注释已经写得很详细了
const User = {
template: `
<h1>
我是{{$route.params.id}}
</h1>
`,
/*
组件内的守卫,就是在路由到对应组件的时候谁调用
直白一点就是,这个路由那个组件显示就调用哪个组件的
钩子函数
*/
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
// 因为此守卫无法访问组件的实例,所以可以可选的给next传入一个回调,Vue会将对应组件的实例传到回调的第一个参数
next(vm =>{
// vm就是对应组件的实例
// 此钩子函数是唯一一个支持next传回调的钩子,因为这个钩子函数无法获取组件的实例,所以需要这么做
console.log(vm);
});
},
// 2.2+
beforeRouteUpdate(to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
next();
},
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
// 在离开路由前调用此组件,可以做一些离开此组件前的最后确认工作
// 比如提醒用户一些需要的信息让其是否确认离开当前组件
next();
}
}
完整的导航解析流程
- 导航被触发。
- 在失活的组件里调用离开守卫。
- 调用全局的 beforeEach 守卫。
- 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
- 在路由配置里调用 beforeEnter。
- 解析异步路由组件。
- 在被激活的组件里调用 beforeRouteEnter。
- 调用全局的 beforeResolve 守卫 (2.5+)。
- 导航被确认。
- 调用全局的 afterEach 钩子。
- 触发 DOM 更新。
- 用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。
路由元信息
可以定义meta字段在导航守卫中通过对应的逻辑判断此meta字段做出不同的逻辑,直接贴官方教程了,3分钟就会
过渡动效
<router-view> 是基本的动态组件,所以我们可以用 <transition> 组件给它添加一些过渡效果,支持transition的所有属性
<transition>
<router-view></router-view>
</transition>
- 单个路由组件的过渡
上面的用法会给所有路由设置一样的过渡效果,如果你想让每个路由组件有各自的过渡效果,可以在各路由组件内使用 <transition> 并设置不同的 name。
const Foo = {
template: `
<transition name="slide">
<div class="foo">...</div>
</transition>
`
}
const Bar = {
template: `
<transition name="fade">
<div class="bar">...</div>
</transition>
`
}
官网文档3分钟保证掌握
数据获取
有时候我们进入一个路由需要向服务器获取某些数据决定组件怎样呈现,这时候Vue提供了两种解决方案
- 导航完成后获取
当你使用这种方式时,我们会马上导航和渲染组件,然后在组件的 created 钩子中获取数据。这让我们有机会在数据获取期间展示一个 loading 状态,还可以在不同视图间展示不同的 loading 状态。
<template>
<div class="post">
<div class="loading" v-if="loading">
Loading...
</div>
<div v-if="error" class="error">
{{ error }}
</div>
<div v-if="post" class="content">
<h2>{{ post.title }}</h2>
<p>{{ post.body }}</p>
</div>
</div>
</template>
export default {
data () {
return {
loading: false,
post: null,
error: null
}
},
created () {
// 组件创建完后获取数据,
// 此时 data 已经被 observed 了
this.fetchData()
},
watch: {
// 如果路由有变化,会再次执行该方法
'$route': 'fetchData'
},
methods: {
fetchData () {
this.error = this.post = null
this.loading = true
// replace getPost with your data fetching util / API wrapper
getPost(this.$route.params.id, (err, post) => {
this.loading = false
if (err) {
this.error = err.toString()
} else {
this.post = post
}
})
}
}
}
- 导航完成前获取
通过这种方式,我们在导航转入新的路由前获取数据。我们可以在接下来的组件的 beforeRouteEnter 守卫中获取数据,当数据获取成功后只调用 next 方法。
export default {
data () {
return {
post: null,
error: null
}
},
beforeRouteEnter (to, from, next) {
getPost(to.params.id, (err, post) => {
next(vm => vm.setData(err, post))
})
},
// 路由改变前,组件就已经渲染完了
// 逻辑稍稍不同
beforeRouteUpdate (to, from, next) {
this.post = null
getPost(to.params.id, (err, post) => {
this.setData(err, post)
next()
})
},
methods: {
setData (err, post) {
if (err) {
this.error = err.toString()
} else {
this.post = post
}
}
}
}
在为后面的视图获取数据时,用户会停留在当前的界面,因此建议在数据获取期间,显示一些进度条或者别的指示。如果数据获取失败,同样有必要展示一些全局的错误提醒。
滚动行为
使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。 vue-router 能做到,而且更好,它让你可以自定义路由切换时页面如何滚动。
** 注意: 这个功能只在支持 history.pushState 的浏览器中可用。**
// 路由创建时可以提供一个此方法
scrollBehavior(to, from, savedPosition) {
// 返回期望滚动到的位置
/*
这时候我们切换user组件时就会滚动到1500y的位置
*/
// return {x:0,y:1500}
// if (savedPosition) {
// /*
// 当此函数有return 一个值的话,那么savedPosition就会保存
// return过的值,具体大家可以直接打印看
// */
// console.log(savedPosition);
// return savedPosition;
// } else {
// if(to.hash){
// return {
// // 可以跳转到对应的锚点
// // url最后面#开头的都是锚
// selector:to.hash,
// // vue2.6+新增了一个可选的offset选项
// offset:{x:number,y:number}
// }
// }else return {x:0,y:0}
// }
// 同时2.8vue-router新增了一个异步滚动的特性
// 我们可以直接返回一个promise
return new Promise((resolve, reject) => {
// 会等待一秒钟滚动到y2000的位置
setTimeout(() => {
resolve({ x: 0, y: 2000 });
}, 1000)
})
}
路由懒加载
首先就是会有进阶的几个特性直接用的是链接,第一是觉得非常简单,第二觉得非常难...其实最主要的是因为自己脑袋容量不是很大吧,不过这里还是一样做一个总结吧(我给链接的网址真的3分钟掌握,内容不是很多)
- 创建一个路由
- 引入vue-router
- 创建routes对象(路由匹配规则)
- 通过routes创建vue-router实例
- 将实例挂载到vue实例上
- 路由完成
-
路由传参
- params传参就是路由匹配规则,写path /:id : + 属性名
- path可以使用正则表达式
- 匹配path是自上而下一次匹配,所以我们可以有一个通配符path匹配规则放在最后面就可以实现捕获所有不存在路由(404)
- query传参 这个貌似没有说好像,就是url后面的?key = value这种方式
-
嵌套路由
- 每一个匹配规则都有一个children属性,是一个数组,children里面就是一个匹配规则,里面还可以有children属性
- 匹配子路由path不能写 / 了,vue会自动补充完成路由
- 配置子路由还有一点必须切记,有子路由的组件一定要留坑
router-view
,不然到时候路由跳转渲染不出组件,vue也不会出任何提示,这是最难的
编程式导航
- 路由导航可以通过JavaScript实现
- push replace go都是可以实现路由的跳转
- go是前进后退(如果步数不够就会默默失败)
- 可以传入一个对象跳转路由,对象规则 params传参要么直接 -/user/:id - {path:
/user/${value}
}加上对应的变量,要么使用命名视图 - {name:"/user",params:{ name:"suiyue" }},这样params.name = suiyue了
- 命名路由
- name大多数配合params传参使用
- 如果匹配规则没有name属性的话,那么{name:"/user",params:{ name:"suiyue" }}跳转无效只能path后面直接拼接了
- 命名视图
- 一个路由匹配一个页面,但是真正的一个页面怎么可能就只有一个组件呢,都是拆分出来的多个组件,所以这时候需要用到命名视图了
- 可以让一个路由显示多个组件
-
router-view
加上name属性制定具体的名字,没有指定名字默认为default - 路由匹配规则使用
components
,一个对象,key为router-view
的name,value就是对应显示的组件 - 命名视图可以嵌套,就是在children中写就行了,一定一定一定记得要留
router-view
的坑,不然到时候显示不了组件又没有任何错误,你懂的
- 重定向和别名
- 重定向 redirect可以直接重定向到其他的路由
- 别名,访问别名路由内里其实渲染的就是对应path的组件(访问别名和path都是一样的)
- 路由组件传参
- $route与之对应的路由高度耦合(路由出现错误就会导致组件内无法获得参数)
- 可以在匹配规则中制定props属性
- props有三种类型,
bool ---> 为真会将params对应的键值对设置到组件根元素的属性上
obj ---> 为对象那么此对象对应的键值对就会相应设置到对应组件属性上
func --> 函数可以接收一个route为参数,返回一个对象,也是设置到组件属性上
html5History模式
- 只需要在实例化Vue时添加上
mode:"history"
就可以使用history模式了,但是需要配置好服务器
-
导航守卫
- 全局前置守卫 --> beforeEach
- 全局解析守卫 --> beforeResolve --> 2.5+
- 全局后置钩子 --> afterEach
- 路由独享守卫 -->beforeEnter
- 组件内的守卫
- beforeRouteEnter (next有回调,接收对应组件实例)
- beforeRouteUpdate 2.2+
- beforeRouteLeave
-
完整的导航解析流程
- 导航被触发。
- 在失活的组件里调用离开守卫。
- 调用全局的 beforeEach 守卫。
- 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
- 在路由配置里调用 beforeEnter。
- 解析异步路由组件。
- 在被激活的组件里调用 beforeRouteEnter。
- 调用全局的 beforeResolve 守卫 (2.5+)。
- 导航被确认。
- 调用全局的 afterEach 钩子。
- 触发 DOM 更新。
- 用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。
-
路由元信息
- 定义路由匹配规则时可以加上meta字段是一个对象,元信息,就是用来确定路由的一些信息,通过这些信息我们可以更好的在钩子函数中判断元信息的参数判断是否决定继续路由或者跳转到其他路由(记住next跳转其他路由的坑)
-
过渡动效
我们可以直接给
router-view
包裹一个transition
组件,其实最终router-view
就是一个壳,包裹的还是router-view
对应的组件,相当于每一个组件的切换就像transition
包裹component
一样,通过is改变渲染的组件但是上面的方法决定了所有的组件的动效都会一样的(一个
transition
),可能我们需要在组件切换时加上不同的过渡效果,就需要在每一个组件的内部包裹一个对应的transition(有一点一直没搞懂,就是不知道样式怎么分开写,应该是必须指定一个name吧,不然全都是一样的样式了)
-
数据获取
- 导航完成后获取
- 这种方式会马上导航和渲染组件,然后在新渲染的组件的created钩子中获取数据
- 那么在获取数据的过程中,对应的组件就必须有一个loding图了
- 导航完成前获取
- 这种方式我们会在导航转入新的路由前获取数据
- 在接下来组件的钩子
beforeRouterEnter
守卫中获取数据 - 数据获取成功调用next()方法
- 这样的话就必须在当前的组件中渲染一个进度条或者别的提示了
-
滚动行为
- 可以在实例化vue-router时接收一个
scrollBehavior
函数,通过这个函数我们可以控制路由跳转时的默认滚动行为 - 此函数可以返回一个具体坐标值
{x:0,y:0}
这种 - 每一次
scrollBehavior
函数成功返回一个具体坐标后savedPosition
参数就会记录对应的坐标,下次就可以直接返回了 - 同样可以返回锚点跳转,通过在url传入对应的hash完成
- 2.6+ 中还有一个可选的offset参数可以使用
- 可以在实例化vue-router时接收一个
有一点要给大家说清楚,这里所有的版本要求都是要求的vue-router插件版本,大家会不会以为是vue的版本呢?大家如果学习前端的时候有什么疑惑或者想跟我交流的可以加下QQ群:78484----> 5854 (感谢)