目录
- 1 路由项目简介
- 2 子路由
- 3 路由中参数的传递
- 4 路由表的组件群
- 5 url 传值
- 6 router-link 属性说明
- 7 redirect 重定向
- 8 alias 别名
- 9 watch 监控动画
- 10 404 错误页面处理
- 11 路由生命钩子
- 12 方法导航跳转
- 13 补充
13.1 路由配置为 history,页面刷新找不到路径问题
13.2 路由切换简单动画效果
13.3 组件获取 $route 对象,params 参数转为 props 配置
13.4 路由生命周期补充(包括全局、路由配置、组件中路由生命钩子)
13.5 组件异步加载,路由配置
1 路由项目简介
-
工程入口文件:
-
路由配置:
说明:
1:两种模式:hash 和 h5
mode: 'history', // hash
2:router-view,页面路由对应组件内容展示的位置
<router-view/>
3:router-link,页面路由跳转
<router-link to="/">/</router-link>
2 子路由
配置 children 属性:
{
path: '/form',
name: 'HelloForm',
component: HelloForm, // 必须
children: [
{
// path: '/form/first',
path: 'first',
name: 'FormFirst',
component: FormFirst
},
{
// path: '/form/second',
path: 'second',
name: 'FormFirst',
component: FormSecond
}
]
},
注意:这里 path 路径,上面两种写法都可以
在根路径对应的组件中配置 router-view,用于显示子内容:
HelloForm.js:
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>HelloForm</h2>
<router-view/>
</div>
</template>
页面 router-link 访问:
<li>
<router-link to="/form">from</router-link>
<ol>
<li>
<router-link to="/form/first">
from first
</router-link>
</li>
<li>
<router-link to="/form/second">
from second
</router-link>
</li>
</ol>
</li>
扩展:children 使用绑定方式
children 使用绑定方式:与 path: '/users/id' 做区分:
{
path: '/users',
name: 'HelloList',
component: HelloForm,
children: [
{ path: ':id', component: test },
{ path: 'user/:id', component: tt }
]
},
!!!记得要在父组件 HelloForm,路由为 users,
展示对应的 children 子组件的内容,需要在父组件配置 <router-view/>
访问:
<router-link to="/users/11" exact>users</router-link>
<router-link to="/users/user/1122" exact>users</router-link>
3 路由中参数的传递
- 都是获取 routes 中配置的 name 参数。
- 项目入口文件、组件字符串模板、组件等都可以获取参数 name;
1:router-link to 为 字符串时
<router-link to="/form">from</router-link>
router/index.js:
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import HelloForm from '@/components/HelloForm'
import HelloList from '@/components/HelloList'
Vue.use(Router)
const FormFirst = {
template: `
<div>
{{$route.name}} // !!! 字符串组件模板获取 name 参数。
<h1>FormFirst</h1>
</div>
`
}
const FormSecond = {
template: `
<h1>FormSecond</h1>
`
}
export default new Router({
mode: 'history', // hash
base: __dirname,
routes: [
{
path: '/',
name: 'home',
component: HelloWorld
},
{
path: '/form',
name: 'form00',
component: HelloForm,
children: [
{
// path: '/form/first',
path: 'first',
name: 'FormFirst111',
component: FormFirst
},
{
// path: '/form/second',
path: 'second',
name: 'FormSecond222',
component: FormSecond
}
]
},
{
path: '/list',
name: 'HelloList',
component: HelloList
}
]
})
App.vue:router-link to 为 字符串。
<template>
<div id="app">
{{ $route.name }}
<ol>
<li>
<router-link to="/">/</router-link>
</li>
<li>
<router-link to="/form">from</router-link>
<ol>
<li>
<router-link to="/form/first">
from first
</router-link>
</li>
<li>
<router-link to="/form/second">
from second
</router-link>
</li>
</ol>
</li>
<li>
<router-link to="/list" >list</router-link>
</li>
</ol>
<router-view/>
</div>
</template>
HelloWorld.vue:其中一个组件,可以获取参数。
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>Essential Links</h2>
{{ $route.name }} // 获取参数
</div>
</template>
2:router-link to 为 绑定参数
<router-link :to="{name: 'home', params: {id: 321}}">/</router-link>
注意:name 应该与 routes 中的 name 对应。
App.vue:
<template>
<div id="app">
<img src="./assets/logo.png">
{{ $route.name }}
{{ $route.params.id }} // 获取参数
<ol>
<li>
<router-link :to="{name: 'home', params: {id: 321}}">/</router-link>
</li>
<li>
<router-link :to="{name: 'form00', params: {id: 666}}">from</router-link>
<ol>
<li>
<router-link :to="{name: 'FormFirst111', params: {id: 888}}">
from first
</router-link>
</li>
<li>
<router-link :to="{name: 'FormSecond222', params: {id: 777}}">
from second
</router-link>
</li>
</ol>
</li>
<li>
<router-link :to="{name: 'HelloList', params: {id: 456}}">list</router-link>
</li>
</ol>
<router-view/>
</div>
</template>
HelloWorld.js
<template>
<div class="hello">
<h2>Essential Links</h2>
{{ $route.name }}
{{ $route.params.id }} // 其中一个组件获取参数
</div>
</template>
字符串模板组件
const FormFirst = {
template: `
<div>
{{$route.name}}
{{$route.params.id}} // 字符串模板获取参数
<h1>FormFirst</h1>
</div>
`
}
4 路由表的组件群
router-view 多个模板:如果没有指定 name,则为默认 default,如果有 name,需要和 components 对象中的 key 对应。
{
path: '/',
name: 'home',
components: {
default: HelloWorld,
left: FormFirst,
right: FormSecond
}
},
{
path: '/list',
name: 'HelloList',
components: {
default: FormFirst,
left: FormFirst,
right: FormSecond
}
},
<template>
<div id="app">
<ol>
<li>
<router-link :to="{name: 'home', params: {id: 321}}">/</router-link>
</li>
<li>
<router-link :to="{name: 'form00', params: {id: 666}}">from</router-link>
<ol>
<li>
<router-link :to="{name: 'FormFirst111', params: {id: 888}}">
from first
</router-link>
</li>
<li>
<router-link :to="{name: 'FormSecond222', params: {id: 777}}">
from second
</router-link>
</li>
</ol>
</li>
<li>
<router-link :to="{name: 'HelloList', params: {id: 456}}">list</router-link>
</li>
</ol>
<router-view/>
<router-view name="left"/>
<router-view name="right"/>
</div>
</template>
5 url 传值
5.2 params
{
path: '/:id?/', // id 有无都可以
name: 'home',
components: {
default: HelloWorld,
left: FormFirst,
right: FormSecond
}
},
{
path: '/list/:id/:name', // 需要 id 和 name
name: 'HelloList',
component: HelloList
},
{
path: '/list/:id/:name', // 正则表达式
name: 'HelloList',
component: HelloList
},
<router-link :to="{name: 'HelloList', params: {id: 1, name: 'xiaoming1'}}">list</router-link>
<router-link to="/list/1/xiaoming">list2</router-link>
组件获取对应的 url 参数:
{{ $route.params.id }} - {{ $route.params.name }}
注意:
如果出现 Vue Router 跳转到页面后,点击当前的导航导致 URL 又在后面加了一段重复的当前路径的错误,原因如下:
{
path: '/list/:id/:name',
name: 'HelloList',
component: HelloList
}
<router-link to="list/1/xiaoming">list2 相对路由 错误!!!</router-link>
<router-link to="/list/1/xiaoming">list3 绝对路由</router-link>
5.2 query
<router-link :to="{path: '/test', query: {id: 222, age: 122}}" >测试</router-link>
获取参数:
{{ $route.query.age }}
说明:
params 是和 name 配置使用的,而 query 是和 path 配置使用。获取参数为 {{route.query.xx}}
6 router-link 属性说明
扩展:给 router-link 新增样式
.router-link-exact-active,
.router-link-active {
color: red;
}
6.1 activeClass
activeClass:选中状态,添加的 class
<router-link to="/list" activeClass='myClass' >测试</router-link>
6.2 append
append:相对路径添加
<router-link to="list" append>测试</router-link>
如果为:绝对路径,则无效
<router-link to="/list" append>测试</router-link>
6.3 exact
exact:精准匹配
如果没有 exact,则访问路径为 /test/tt,也会匹配 /test。如下:
<router-link to="/test/tt" exact>测试1</router-link>
<router-link to="/test" >测试2</router-link>
如果使用 exact,则为精准匹配, /test/tt,不会匹配 /test。
<router-link to="/test/tt" exact>测试1</router-link>
<router-link to="/test" exact>测试2</router-link>
7 redirect 重定向
方式一:简单跳转
{
path: '/cdx',
redirect: '/test'
},
{
path: '/test',
name: 'HelloList',
component: test
},
页面访问:
<router-link to="/cdx">测试重定向</router-link>
方式二:带参数
{
path: '/cdx/:id',
redirect: '/users/:id'
},
{
path: '/users',
name: 'HelloList',
component: HelloForm,
children: [
{ path: ':id', component: test }, // 记得要在父组件 HelloForm,路由为 users,展示对应的 children 子组件的内容,需要在父组件配置 <router-view/>
{ path: 'user/:id', component: tt }
]
},
页面访问:
<router-link to="/cdx/111">测试重定向</router-link>
方式三:函数处理
{
path: '/cdx/:id',
redirect: param => {
console.log(param) // 经常使用 hash、query、params 等参数
return '/'
}
},
页面访问:
<router-link to="/cdx/111">测试重定向</router-link>
8 alias 别名
{
path: '/test',
name: 'HelloList',
component: test,
alias: ['/tttt', '/gg']
},
<router-link to="/gg" exact>别名1</router-link>
<router-link :to="{path: '/tttt', query: {id: 222}}" >别名2</router-link>
9 watch 监控动画
watch 监听动画在 App.vue 文件。
watch: {
$route(to, from) {
console.log(to, from);
if (to.path === '/users/11') {
this.name = 'fade1';
} else {
this.name = 'fade';
}
}
}
<template>
<div id="app">
<ol>
<li>
<router-link :to="{name: 'home', params: {id: 321}}" exact>/</router-link>
</li>
<li>
<router-link to="/users/user/1122" exact>users</router-link>
</li>
<li>
<router-link :to="{path: '/test', query: {id: 222, age: 122}}" >测试2</router-link>
</li>
<li>
<router-link to="/cdx/111">测试重定向</router-link>
</li>
</ol>
<transition :name="name" mode="out-in">
<router-view/>
</transition>
</div>
</template>
<script>
export default {
data() {
return {
name: 'fade'
};
},
watch: {
$route(to, from) {
console.log(to, from);
if (to.path === '/users/11') {
this.name = 'fade1';
} else {
this.name = 'fade';
}
}
}
};
</script>
<style>
/* scoped */
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
ol {
width: 144px;
text-align: left;
}
.router-link-exact-active {
color: red;
}
.fade-enter,
.fade-leave-active {
opacity: 0;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s;
}
</style>
10 404 错误页面处理
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
Vue.use(Router)
export default new Router({
mode: 'hash', // hash history
base: __dirname,
routes: [
{
path: '/',
name: 'home',
components: {
default: HelloWorld
}
},
{
path: '/test',
name: 'HelloList',
component: test
},
{ path: '*', component: Page404 }
]
})
11 路由生命钩子
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
Vue.use(Router)
const test = {
template: `
<h1>test</h1>
`,
beforeRouteEnter(to, from, next) {
console.log('beforeRouteEnter', to, from)
next()
},
beforeRouteLeave(to, from, next) {
console.log('beforeRouteLeave', to, from)
next()
}
}
const Page404 = {
template: `
<h1>Page404 error</h1>
`
}
export default new Router({
mode: 'hash', // hash history
base: __dirname,
routes: [
{
path: '/',
name: 'home',
components: {
default: HelloWorld
}
},
{
path: '/test',
name: 'HelloList',
component: test,
beforeEnter: (to, from, next) => {
console.log('beforeEnter', to, from);
// next(false); // 不允许进入,或者不写
// next({ path: '/dsds' }) // 重定向
next() // 允许
}
},
{ path: '*', component: Page404 }
]
})
注意:beforeEnter 是在 routes 路由里面配置的,而 beforeRouteEnter 和 beforeRouteLeave 是在对应的组件中。
参数说明:
- 如果没有写 next ,或者 next(false) 表示不跳转;
- 而 next() 表示默认跳转;
- next({ path: '/dsds' }) 也可以对象相关配置,重定向等。
12 方法导航跳转
<template>
<div id="app">
<button @click="qianjin">前进</button>
<button @click="houtui">后退</button>
<button @click="home">home</button>
<button @click="query">query</button>
<ol>
<li>
<router-link :to="{name: 'home', params: {id: 321}}" exact>/</router-link>
</li>
<li>
<router-link to="/test">test</router-link>
</li>
</ol>
<transition :name="name" mode="out-in">
<router-view/>
</transition>
</div>
</template>
<script>
export default {
data() {
return {
name: 'fade'
};
},
methods: {
qianjin: function() {
this.$router.go(1);
},
houtui: function() {
this.$router.go(-1);
},
home: function() {
this.$router.push('/');
},
query: function() {
this.$router.push({ path: '/test', query: { plan: 'private' } });
}
}
};
</script>
<style>
/* scoped */
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
ol {
width: 144px;
text-align: left;
}
.router-link-exact-active {
color: red;
}
.fade-enter,
.fade-leave-active {
opacity: 0;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s;
}
</style>
13 补充
13.1 路由配置为 history,页面刷新找不到路径问题
当设置路由为 history 路由时,没有配置 nginx 重定向,当页面刷新的时候,会根据路由路径请求后台资源,这时候会报路径错误,因为不会重定向到路由配置页;所以,解决方法也可以通过配置 webpack 解决。
- 在配置 webpack-dev-server 的地方新增 historyApiFallBack 配置:
const devServer = {
port: 8888,
host: '0.0.0.0',
...
historyApiFallBack : {
index: '/index.html'
}
}
- 注意:配置的路径跟 output 路径有关系,如果有配置 output 中 有配置 publicPath,那也需要在 historyApiFallBack 中的 index 路径前面配置。
如:output 配置:
output: {
filename: 'bundle.[hash:8].js',
path: path.join(__dirname, '../dist'),
publicPath: '/public/'
},
则 historyApiFallBack 中的 index 路径配置为:
historyApiFallBack : {
index: '/public/index.html'
}
13.2 路由切换简单动画效果
<transition name='fade'>
<router-view />
</transition>
.fade-enter-active, .fade-leave-active {
transition: opacity .5s
}
.fade-enter, .fade-leave-to {
opacity: 0
}
13.3 组件获取 $route 对象,params 参数转为 props 配置
方式一,前面介绍可以通过 this.$route 对象获取:
mounted () {
console.log(this.$route)
}
方式二:在配置路由组件, 利用 props (布尔、对象、函数)传递对应的配置路由参数,把参数转为 props
{
path: '/app/:id',
props: true, // 把 path: '/app/:id' 中的 id 参数,转化为 props 属性传递给组件 Todo,Todo 可以通过 props 获取到 id,不用通过 this.$route.params.id 获取 。
component: Todo,
name: 'app',
meta: {
title: 'this is app',
description: 'xxxx'
}
}
props 也可以为对象或者函数,如:
...
props: {
id: '111'
},
...
...
props: (route) => ({id: route.query.xx})
...
13.4 路由生命周期补充(包括全局、路由配置、组件中路由生命钩子)
- 1 全局导航钩子(全局路由)
beforeEach、beforeResolve、afterEach
cosnt router = createRouter();
router.beforeEach((to, from, next) => {
console.log('before each invoked');
if (to.fullPath === '/login') {
next();
}
})
router.beforeResolve((to, from, next) => {
console.log('before resolve invoked');
if (to.fullPath === '/login') {
next();
}
})
router.afterEach((to, from) => {
console.log('after each invoked');
})
例子:验证用户登录,才显示的路由路径
router.beforeEach((to, from, next) => {
console.log('before each invoked');
if (to.fullPath === '/app') {
next({path: '/login'});
} else {
next();
}
})
- 2 App 路由配置中的钩子:
beforeEnter
{
path: '/app',
name: 'app',
...
beforeEnter (to, from, next) {
next()
}
}
- 3 组件内路由钩子
beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
export default{
data () {
return {
id: xxx
}
},
beforeRouteEnter (to, from, next) {
next();
},
beforeRouteUpdate(to, from, next) {
next();
},
beforeRouteLeave(to, from, next) {
next();
}
}
说明:
1:beforeRouteRupdate 触发的时候,需要路由加载的是同一个,例如根据参数 id 的不同,加载的组件还是一样的,这时候 beforeRouteRupdate 钩子就会触发。
{
path: '/app/:id',
component: Todo,
name: 'app',
...
}
组件是一样的 Todo,但是 id 参数不一样的时候,就会触发 beforeRouteRupdate 钩子
2:进入页面之前的验证,因为在 beforeRouteEnter 钩子,页面还没有加载,所以,不能获取该页面的数据,可以通过 next 回调方法;
beforeRouteEnter (to, from, next) {
console.log(' 组件进入之前', this); // undefined
next(vm => {
console.log('组件已经进入', vm.id)
})
}
3:通过 beforeRouteLeave 钩子,控制页面离开行为,例如表单很多的时候,提示是否离开
beforeRouteLeave (to, from, next) {
if (global,confirm('确定离开该页面吗?')) {
next();
}
}
13.5 组件异步加载,路由配置
异步加载对应路由的代码,而不是一次性加载所有页面代码。优化加快首屏加载的速度。
1:component 写法,通过函数 import 对应的组件:
{
path: '/app/:id',
props: true,
component: () => import('../views/todo.vue'), // !!!
name: 'app',
...
}
2:安装 babel-plugin-syntax-dynamic-import 包:
npm i babel-plugin-syntax-dynamic-import -D
3:配置 babel:syntax-dynamic-import
{
"plugins": {
"tansform-vue-jsx",
"syntax-dynamic-import"
}
}