前言:

本文内容:嵌套路由、参数传递及重定向、404和路由钩子

推荐免费Vue基础教程视频:【狂神说Java】Vue最新快速上手教程通俗易懂_哔哩哔哩_bilibili

Vue笔记代码下载地址:

蓝奏云:下载地址 密码:joker

百度云:下载地址 提取码:gwam

嵌套路由

嵌套路由又称子路由,在实际应用中,通常由多层嵌套的组件组合而成。同样,URL中各段动态路径也按照某种结构对应嵌套的各层组件,

1
2
3
4
5
6
7
8
/user/johnny/profile                   /user/johnny/posts
+------------------+ +-----------------+
| User | | User |
| +--------------+ | | +-------------+ |
| | Profile | | +------------> | | Posts | |
| | | | | | | |
| +--------------+ | | +-------------+ |
+------------------+ +-----------------+
  1. 用户信息组件,在views/user目录创建一个名为Profile.vue的视图组件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <template>
    <h1>个人信息</h1>
    </template>

    <script>
    export default {
    name: "UserProfile"
    }
    </script>

    <style scoped>

    </style>
  2. 用户列表组件,在views/user目录创建一个名为List.vue的视图组件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <template>
    <h1>用户列表</h1>
    </template>

    <script>
    export default {
    name: "UserList"
    }
    </script>

    <style scoped>

    </style>
  3. 配置嵌套路由修改router目录下的index.js路由配置文件

    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    <template>
    <div>
    <el-container>
    <el-aside width="200px">
    <el-menu :default-openeds="['1']">
    <el-submenu index="1">
    <template slot="title"><i class="el-icon-caret-right"></i>用户管理</template>
    <el-menu-item-group>
    <el-menu-item index="1-1">
    <router-link to="/user/profile">个人信息</router-link>
    </el-menu-item>
    <el-menu-item index="1-2">
    <router-link to="/user/list">用户列表</router-link>
    </el-menu-item>
    </el-menu-item-group>
    </el-submenu>

    <el-submenu index="2">
    <template slot="title"><i class="el-icon-caret-right"></i>内容管理</template>
    <el-menu-item-group>
    <el-menu-item index="2-1">分类管理</el-menu-item>
    <el-menu-item index="2-2">内容列表</el-menu-item>
    </el-menu-item-group>
    </el-submenu>
    </el-menu>
    </el-aside>

    <el-container>
    <el-header style="text-align: right; font-size: 12px;">
    <el-dropdown>
    <i class="el-icon-setting" style="margin-right: 15px"></i>
    <el-dropdown-menu slot="dropdown">
    <el-dropdown-item>个人信息</el-dropdown-item>
    <el-dropdown-item>退出登录</el-dropdown-item>
    </el-dropdown-menu>
    </el-dropdown>
    </el-header>

    <el-main>
    <router-view/>
    </el-main>
    </el-container>
    </el-container>
    </div>
    </template>

    <script>
    export default {
    name: "Main"
    }
    </script>

    <style scoped lang="scss">
    .el-header{
    background-color: #B4C0D1;
    color: #333;
    line-height: 60px;
    }
    .el-aside{
    color: #333;
    }
    </style>

  4. 修改router文件夹下的index.js

    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
    import Vue from 'vue'
    import Router from 'vue-router'

    import Main from '../views/Main'
    import Login from '../views/Login'

    import UserList from '../views/user/List'
    import UserProfile from '../views/user/Profile'


    Vue.use(Router)


    export default new Router({
    routes:[
    {
    path: '/main',
    component: Main,// 嵌套路由
    children: [
    {path: '/user/profile',component: UserProfile},
    {path: '/user/list',component: UserList}
    ]
    },
    {
    path: '/login',
    component: Login
    }
    ]
    });
  5. 运行测试

    测试地址:hello-vue

参数传递及重定向

  1. 修改Main.vue,添加参数传递

    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    <template>
    <div>
    <el-container>
    <el-aside width="200px">
    <el-menu :default-openeds="['1']">
    <el-submenu index="1">
    <template slot="title"><i class="el-icon-caret-right"></i>用户管理</template>
    <el-menu-item-group>
    <el-menu-item index="1-1">
    <!-- 参数传递 name: 传组件名 params 传递参数 需要对象-->
    <router-link :to="{name: 'UserProfile',params:{id:1}}">个人信息</router-link>
    </el-menu-item>
    <el-menu-item index="1-2">
    <router-link to="/user/list">用户列表</router-link>
    </el-menu-item>
    <el-menu-item index="1-3">
    <router-link to="/goHome">回到首页</router-link>
    </el-menu-item>
    </el-menu-item-group>
    </el-submenu>

    <el-submenu index="2">
    <template slot="title"><i class="el-icon-caret-right"></i>内容管理</template>
    <el-menu-item-group>
    <el-menu-item index="2-1">分类管理</el-menu-item>
    <el-menu-item index="2-2">内容列表</el-menu-item>
    </el-menu-item-group>
    </el-submenu>
    </el-menu>
    </el-aside>

    <el-container>
    <el-header style="text-align: right; font-size: 12px;">
    <el-dropdown>
    <i class="el-icon-setting" style="margin-right: 15px"></i>
    <el-dropdown-menu slot="dropdown">
    <el-dropdown-item>个人信息</el-dropdown-item>
    <el-dropdown-item>退出登录</el-dropdown-item>
    </el-dropdown-menu>
    </el-dropdown>
    <span>{{name}}</span>
    </el-header>

    <el-main>
    <router-view/>
    </el-main>
    </el-container>
    </el-container>
    </div>
    </template>

    <script>
    export default {
    props: ['name'],
    name: "Main"

    }
    </script>

    <style scoped lang="scss">
    .el-header{
    background-color: #B4C0D1;
    color: #333;
    line-height: 60px;
    }
    .el-aside{
    color: #333;
    }
    </style>
  2. 修改router文件下index.js

    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
    32
    33
    34
    35
    import Vue from 'vue'
    import Router from 'vue-router'

    import Main from '../views/Main'
    import Login from '../views/Login'

    import UserList from '../views/user/List'
    import UserProfile from '../views/user/Profile'


    Vue.use(Router)


    export default new Router({
    routes:[
    {
    path: '/main/:name',
    component: Main,// 嵌套路由
    props: true,
    children: [
    // name: 必须在单引号内 props: true 解耦
    {path: '/user/profile/:id',name: 'UserProfile',component: UserProfile,props: true},
    {path: '/user/list',component: UserList}
    ]
    },
    {
    path: '/login',
    component: Login
    },{
    // 重定向
    path: '/goHome',
    redirect: '/main'
    }
    ]
    });
  3. 修改Profile.vue,接收参数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <template>
    <!-- 展示内容必须在标签内 -->
    <div>
    <h1>个人信息</h1>
    <!-- 接收参数方式1-->
    id:{{$route.params.id}}
    <!-- 接收参数方式2-->
    id:{{id}}
    </div>
    </template>

    <script>
    export default {
    //接收参数方式2
    props: ['id'],
    name: "UserProfile"
    }
    </script>

    <style scoped>

    </style>
  4. 修改Login.vue,将登录用户名传递到首页

    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    <template>
    <div>
    <el-form ref="loginForm" :model="form" :rules="rules" label-width="80px" class="login-box">
    <h3 class="login-title">欢迎登录</h3>
    <el-form-item label="账号" prop="username">
    <el-input type="text" placeholder="请输入账号" v-model="form.username"/>
    </el-form-item>
    <el-form-item label="密码" prop="password">
    <el-input type="password" placeholder="请输入密码" v-model="form.password"/>
    </el-form-item>
    <el-form-item>
    <el-button type="primary" v-on:click="onSubmit('loginForm')">登录</el-button>
    </el-form-item>
    </el-form>

    <el-dialog
    title="温馨提示"
    :visible.sync="dialogVisible"
    width="30%"
    :before-close="handleClose">
    <span>请输入账号和密码</span>
    <span slot="footer" class="dialog-footer">
    <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
    </span>
    </el-dialog>
    </div>
    </template>

    <script>
    export default {
    name: "Login",
    data(){
    return {
    form: {
    username : '',
    password : ''
    },
    // 表单验证 需要在el-form-item元素中增加prop属性
    rules: {
    username: [
    {required: true,message: '账号不能为空',trigger: 'blur'}
    ],
    password: [
    {required: true,message: '密码不能为空', trigger: 'blur'}
    ]
    },
    // 对话框显示和隐藏
    dialogVisible: false
    }
    },
    methods: {
    onSubmit(formName){
    // 表单绑定验证
    this.$refs[formName].validate((valid) => {
    if(valid) {
    // 使用 vue-router 路由到指定页面 该方式称为编程式导航
    this.$router.push("/main/"+this.form.username);
    }else{
    this.dialogVisible = true;
    return false;
    }
    });
    }
    }
    }
    </script>

    <style scoped>
    .login-box {
    border: 1px solid #DCDFE6;
    width: 350px;
    margin: 180px auto;
    padding: 35px 35px 15px 35px;
    border-radius: 5px;
    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
    box-shadow: 0 0 25px #909399;
    }
    .login-title{
    text-align: center;
    margin: 0 auto 40px auto;
    color: #303133;
    }
    </style>
  5. 运行测试

    测试地址:hello-vue

404和路由钩子

路由模式和404

路由模式有两种

修改路由配置,代码如下:

1
2
3
4
5
export default new Router({
mode: 'history',
routes: [
]
});

处理404创建一个名为NotFound.vue的视图组件,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<div>
<h1>你的页面走丢了</h1>
</div>
</template>

<script>
export default {
name: "NotFound"
}
</script>

<style scoped>

</style>

修改router文件夹下的index.js

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
32
33
34
35
36
37
38
39
import Vue from 'vue'
import Router from 'vue-router'

import Main from '../views/Main'
import Login from '../views/Login'

import UserList from '../views/user/List'
import UserProfile from '../views/user/Profile'
import NotFound from '../views/NotFound'

Vue.use(Router)


export default new Router({
routes:[
{
path: '/main/:name',
component: Main,// 嵌套路由
props: true,
children: [
// name: 必须在单引号内 props: true 解耦
{path: '/user/profile/:id',name: 'UserProfile',component: UserProfile,props: true},
{path: '/user/list',component: UserList}
]
},
{
path: '/login',
component: Login
},{
// 重定向
path: '/goHome',
redirect: '/main'
},{
// 404
path: '*',
component: NotFound
}
]
});

路由钩子与异步请求

beforeRouteEnter:在进入路由前执行

beforeRouteLeave:在离开路由前执行

修改Profile.vue

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
32
33
<template>
<!-- 展示内容必须在标签内 -->
<div>
<h1>个人信息</h1>
<!-- 接收参数方式1-->
id:{{$route.params.id}}
<!-- 接收参数方式2-->
id:{{id}}
</div>
</template>

<script>
export default {
//接收参数方式2
props: ['id'],
name: "UserProfile",
// 路由钩子
// 进入前执行
beforeRouteEnter: (to,from,next)=>{
console.log('进入路由前');
next();
},
// 离开前执行
beforeRouteLeave: (to,from,next)=>{
console.log('离开路由前');
next();
}
}
</script>

<style scoped>

</style>

参数说明:

  • to:路由将要跳转的路径信息
  • from:路径跳转前的路径信息
  • next:路由的控制参数
    • next()跳入下一个页面
    • next('/path')改变路由的跳转方向,使其跳到另一个路由
    • next(false)返回原来的页面
    • next((vm)=>{})仅在beforeRouteEnter中可用,vm是组件实例

钩子函数中使用异步请求

  1. 安装Axiosnpm install --save axios vue-axios

  2. main.js引用Axios

    1
    2
    3
    4
    // Axios
    import axios from 'axios';
    import VueAxios from 'vue-axios'
    Vue.use(VueAxios, axios)
  3. 在static下新建mock文件夹,在mock下新建data.json

    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
    {
    "name":"Joker大雄",
    "url": "http://jokerdig.com",
    "page": "1",
    "isNonProfit":"true",
    "address": {
    "street": "南稍门",
    "city":"陕西西安",
    "country": "中国"
    },
    "links": [
    {
    "name": "哔哩哔哩",
    "url": "https://www.bilibili.com/"
    },
    {
    "name": "Bing",
    "url": "https://cn.bing.com/"
    },
    {
    "name": "百度",
    "url": "https://www.baidu.com/"
    }
    ]
    }
  4. 修改Profile.vue文件

    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    <template>
    <!-- 展示内容必须在标签内 -->
    <div>
    <h1>个人信息</h1>
    <!-- 接收参数方式1-->
    id:{{$route.params.id}}
    <!-- 接收参数方式2-->
    id:{{id}}
    </div>
    </template>

    <script>
    export default {
    //接收参数方式2
    props: ['id'],
    name: "UserProfile",
    // 路由钩子
    // 进入前执行
    beforeRouteEnter: (to,from,next)=>{
    console.log('进入路由前');
    next(vm=>{
    vm.getData(); // 进入之前执行方法
    });
    },
    // 离开前执行
    beforeRouteLeave: (to,from,next)=>{
    console.log('离开路由前');
    next();
    },
    methods: {
    getData: function(){
    this.axios({
    method: 'get',
    // 这里是将mode改为history后的访问地址
    url: 'http://localhost:8099/static/mock/data.json'
    }).then(function (response){
    console.log(response)
    });
    }
    }
    }
    </script>

    <style scoped>

    </style>

  5. 运行测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    控制台显示:
    进入路由前
    Profile.vue?5da6:37
    Object
    config: {transitional: {…}, transformRequest: Array(1), transformResponse: Array(1), timeout: 0, adapter: ƒ, …}
    data: {name: 'Joker大雄', url: 'http://jokerdig.com', page: '1', isNonProfit: 'true', address: {…}, …}
    headers: {accept-ranges: 'bytes', content-length: '443', content-type: 'application/json; charset=UTF-8', date: 'Fri, 08 Jul 2022 06:07:58 GMT', etag: 'W/"1bb-k3q4Fi2fLrs6JHFRVK6Xr9nXKU8"', …}
    request: XMLHttpRequest {onreadystatechange: null, readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, …}
    status: 200
    statusText: "OK"
    [[Prototype]]: Object