Vue从零开始之VueRouter

    技术2026-03-03  10

    文章目录

    VueRouter路由安装vue-router插件VueRouter+ElementUI基本使用创建项目,安装依赖修改目录结构创建首页视图创建登录页视图创建路由配置导入路由和ElementUI模板中渲染组件 路由匹配规则路由跳转标签代码方式进行跳转 VueRouter 动态路由 r o u t e 路 由 记 录 和 route路由记录和 routerouter路由实例 VueRouter 参数传递使用params的方式传递参数接收参数 使用query方式传递参数接收参数 使用 props 的方式传递参数接收参数 嵌套路由VueRouter重定向VueRouter 路由模式与 404路由模式处理 404 路由元信息路由钩子(导航守卫)全局钩子路由独享的守卫组件内钩子 Axios异步请求 路由懒加载按组分块 keep-alive结合router-view命名视图(一个路由同时渲染多个组件)

    VueRouter路由

    Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。

    安装vue-router插件

    vue-router 是一个插件包,所以我们还是需要用 npm/cnpm 来进行安装的。打开命令行工具,进入你的项目目录,输入下面命令。

    npm install vue-router --save --registry=https://registry.npm.taobao.org

    VueRouter+ElementUI基本使用

    ElementUI,下面是根据vuecli2安装的ElementUI.vuecli3可使用插件安装

    创建项目,安装依赖

    # 使用 webpack 打包工具初始化一个名为 hello-vue-element 的工程 vue init webpack hello-vue-element # 进入工程目录 cd hello-vue-element # 安装 vue-router npm install vue-router --save --registry=https://registry.npm.taobao.org # 安装 element-ui npm i element-ui -S --registry=https://registry.npm.taobao.org # 安装 SASS 加载器,运行时如果报如下错误: Module build failed: TypeError: this.getResolve is not a function 原因是当前sass的版本太高 npm install sass-loader@7.3.1 node-sass --save-dev --registry=https://registry.npm.taobao.org # 安装依赖初始化 npm install --registry=https://registry.npm.taobao.org #启动 npm run dev

    修改目录结构

    在源码目录中创建如下结构:

    assets:用于存放资源文件components:用于存放 Vue 功能组件views:用于存放 Vue 视图组件router:用于存放 vue-router 配置

    创建首页视图

    在 views 目录下创建一个名为 Main.vue 的视图组件;该组件在当前章节无任何作用,主要用于登录后展示登录成功的跳转效果;

    <template> <div> 首页 </div> </template> <script> export default { name: "Main" } </script> <style scoped> </style>

    一个组件页面里只能有一个根元素

    创建登录页视图

    在 views 目录下创建一个名为 Login.vue 的视图组件,其中 el-* 的元素为 ElementUI 组件;

    <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> <!--提交的loginForm为表单的 ref--> <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"); } else { this.dialogVisible = true; return false; } }); } } } </script> <style lang="scss" 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>

    创建路由配置

    在 router 目录下创建一个名为 index.js 的 vue-router 路由配置文件

    import Vue from 'vue' import Router from 'vue-router' import Login from "@/views/Login" import Main from '@/views/Main' // 通过Vue.use(插件),安装插件,默认执行插件的install方法 Vue.use(Router); export default new Router({ // 注意拼写,不要写成routers // 匹配的优先级就按照路由的定义顺序 routes: [ { // 登录页 path: '/login', // 命名路由,非必选项,跳转时与跳转方法的name属性匹配 name: 'Login', component: Login }, { // 首页 path: '/main', name: 'Main', component: Main } ] });

    导入路由和ElementUI

    修改 main.js 入口代码

    import Vue from 'vue' import App from './App' //导入自定义路由配置, 如果/index.js前面是目录可省略不写 import router from './router' // 导入 ElementUI import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' Vue.config.productionTip = false // 安装 ElementUI Vue.use(ElementUI); new Vue({ el: '#app', components: { App }, template: '<App/>', // 启用路由 router, // 启用 ElementUI render: h => h(App) });

    模板中渲染组件

    修改 App.vue 组件代码,渲染组件

    <template> <div id="app"> <router-link to="/main">跳转首页</router-link> <router-view/> </div> </template> <script> export default { name: 'App', } </script>

    VueRouter定义的两个全局标签:

    router-link: 默认会被渲染成一个 a 标签,to 属性为指定链接router-view: 会将url中路由匹配到的组件,在标签所在位置渲染

    路由匹配规则

    path: '/' //根或缺省 path: '' //根或缺省 path: '/params/:foo // :动态路由 path: '/optional-params/:foo?' // ?表示可选参数 path: '/params-with-regex/:id(\\d+)' // 参数后紧跟的括号里可以使用正则 path: '/asterisk/*' // *通配 path: '/optional-group/(foo/)?bar' // ()? 表示路径中的一部分可选

    路由跳转

    标签

    router-link标签的属性:

    to: 指定跳转路径 to使用v-bind绑定后可以传对象,具体用法同router.push(). tag: 指定router-link会被渲染成什么标签active-class: 当router-link对应的路由匹配成功时,会自动给当前元素添加一个名为router-link-active的class. 使用active-class修改添加的class的名字.(可以在路由配置中使用linkActiveClass属性统一修改)replace: 表示跳转时使用replace函数,无法前进后退.(不添加时默认使用push函数)

    当router-link对应的路由匹配成功时,会自动给当前元素添加一个名为router-link-active的class,可根据这个class修改标签路由匹配后的样式

    <router-link to="/main" tag='button' active-class='active' replace >跳转首页</router-link> // 统一修改active-class export default new Router({ routes: [ { // 登录页 path: '/login', // 命名路由,非必选项 name: 'Login', component: Login } ], linkActiveClass: 'active' });

    代码方式进行跳转

    不要使用history绕过VueRouter修改路径

    在 Vue 实例内部,你可以通过 this.$router 访问路由实例。进行路由跳转

    router.push(location, onComplete?, onAbort?) // 字符串 router.push('home') // 字符串格式时传入data中的属性值 router.push('/home/'+ this.id) // 对象 router.push({ path: 'home' }) // 命名的路由 , 变成 /user/123 router.push({ name: 'user', params: { userId: '123' }}) // 带查询参数,变成 /register?plan=private router.push({ path: 'register', query: { plan: 'private' }}) 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

    注意:如果使用了 path,params 会被忽略,同样的规则也适用于 router-link 组件的 to 属性。

    router.replace(location, onComplete?, onAbort?): 跟 router.push 很像,唯一的不同就是,它不会向 history 添加新记录.router.go(n): 类似js的 history.go(n)。

    VueRouter 动态路由

    使用动态路径参数(以冒号开头)把某种模式匹配到的所有路由,全都映射到同个组件。

    const router = new VueRouter({ routes: [ // 动态路径参数 以冒号开头 { path: '/user/:id', component: User } ] }) /user/foo 和 /user/bar 都将映射到User组件 但 /user 不会映射到User组件

    跳转时传递参数

    // 绑定data中的userId属性,单引号括起来的部分不会被Vue当做变量解析 <router-link :to="'/user/'+userId">个人信息</router-link>

    在路由到的组件中接收传递的参数

    <div>{{ $route.params.id }}</div> 或 new Vue({ computed: { currentTime(){ this.$route.params.id } } })

    r o u t e 路 由 记 录 和 route路由记录和 routerouter路由实例

    $route: 路由记录,即路由配置中routes数组中的一个对象,可用来查看路径参数(params),请求参数(query),路由路径(path),hash等$router: 路由实例,new Router创建的路由,用来进行路由跳转

    VueRouter 参数传递

    使用params的方式

    修改路由配置,主要是在 path属性中增加了 :id 这样的占位符

    {path: '/user/profile/:id', name:'UserProfile', component: UserProfile}

    传递参数

    router-link to方式

    <router-link to="/user/profile/1">个人信息</router-link>

    router-link :to方式

    <router-link :to="{name: 'UserProfile', params: {id: 1}}">个人信息</router-link>

    注意: 此时我们将 to 改为了 :to,是为了传对象参数,不然{}不会被解析. 注意 router-link 中的 name 属性名称 一定要和 路由中的 name 属性名称 匹配,因为这样 Vue 才能找到对应的路由路径;

    代码方式传递

    this.$router.push({ name: 'UserProfile', params: {id: 1}});

    接收参数

    在目标组件中接收路径参数: {{ $route.params.id }}

    使用query方式

    路由配置使用最普通的方式

    {path: '/user/profile', name:'UserProfile', component: UserProfile}

    传递参数

    <router-link :to="{name: 'UserProfile', query: { plan: 'private'}}">query</router-link>

    接收参数

    在目标组件中接收路径参数: {{ $route.query.plan }}

    使用 props 的方式

    在组件中使用 $route 会使之与其对应路由形成高度耦合,从而使组件只能在某些特定的 URL 上使用,限制了其灵活性。使用 props 将组件和路由解耦.

    修改路由配置,主要增加了 props: true 属性

    {path: '/user/profile/:id', name:'UserProfile', component: UserProfile, props: true}

    传递参数

    router-link to方式传递

    <router-link to="/user/profile/2">个人信息</router-link>

    router-link :to方式传递

    <router-link :to="{name: 'UserProfile', params: {id: 1}}">个人信息</router-link>

    代码方式传递

    this.$router.push({ name: 'UserProfile', params: {id: 1}});

    接收参数

    为目标组件增加 props 属性,自动映射 export default { //接收占位符id传递的值 props: ['id'], name: "UserProfile" } //模板中直接使用 {{ id }}

    嵌套路由

    嵌套路由又称子路由,在实际应用中,通常由多层嵌套的组件组合而成。

    创建Profile.vue和List.vue 的视图组件,内容添加个根元素其他默认即可

    修改 router 目录下的 index.js 路由配置文件,代码如下:

    // 用于嵌套的路由组件 import UserProfile from '../views/user/Profile' import UserList from '../views/user/List' .... { path: '/main', name: 'Main', component: Main, // 配置嵌套路由 children: [ { // 默认重定向 /main/posts path: '', redirect: 'posts' }, { // 当 /user/profile匹配成功 // UserProfile会被渲染在 Main 组件的<router-view> 中 path: '/user/profile', component: UserProfile }, { // 当 /main/posts 匹配成功 // UserPosts 会被渲染在 Main 的 <router-view> 中 path: 'posts', component: UserPosts } ] } 以 / 开头的嵌套路径会被当作根路径。可以达到嵌套组件而无须设置嵌套的路径。非 / 开头的嵌套路径会被当做子路径,拼接在父路径之后进行匹配

    Main.vue添加的内容

    <template> <div id="app"> <router-link to="/user/profile">跳转profile</router-link> <router-link to="/main/posts">跳转posts</router-link> <router-view/> </div> </template>

    Main.vue在App.vue渲染, profile和posts在Main.vue中渲染

    VueRouter重定向

    Vue 中的重定向是作用在路径不同但组件相同的情况下,或用于缺省时重定向到首页

    修改路由配置(router/index.js)

    { // 缺省时重定向到/main path: '', // 与 path: '/' 等效 redirect: '/main' }, { path: '/main', name: 'Main', component: Main }, { //将/goHome重定向到/main path: '/goHome', redirect: '/main' }

    组件中使用 <router-link to="/goHome">回到首页</router-link>即可重定向到/main

    VueRouter 路由模式与 404

    路由模式

    路由模式有两种

    hash:路径带 # 符号(默认),如 http://localhost/#/loginhtml5的history:路径不带 # 符号,如 http://localhost/login

    修改路由配置(/router/index.js文件),代码如下:

    export default new Router({ mode: 'history', routes: [ ] });

    使用history模式用户直接访问或者刷新非index.html时,浏览器会绕过VueRouter直接请求后端服务,导致404.后端应进行相应设置

    处理 404

    创建一个视图组件,在路由配置文件(/router/index.js)导入并配置

    //该路由放到最后 { path: '*', component: NotFound }

    路由元信息

    定义路由的时候可以配置 meta 字段:

    const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, meta: { title: '标题1' }, children: [ { path: 'bar', component: Bar, // a meta field meta: { requiresAuth: true } } ] } ] })

    一个路由匹配到的所有路由记录都会保存在$route.matched 数组.我们可以遍历 $route.matched 来检查路由记录中的 meta 字段。

    路由钩子(导航守卫)

    “导航”表示路由正在发生改变。导航守卫主要用来通过跳转或取消的方式守卫导航。导航守卫就是路由的生命周期钩子函数.

    全局钩子

    beforeEach :全局前置钩子afterEach: 全局后置钩子,不接受 next 函数 const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, meta: { title: '标题1' } } ] }) // 每个路由跳转前,将要跳转到的路由记录设置的元信息的title值,设置为网页的title router.beforeEach((to,from,next)=>{ document.title = to.mathed[0].meta.title next() })

    路由独享的守卫

    beforeEnter: 进入路由之前 const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, beforeEnter: (to, from, next) => { // ... } } ] })

    组件内钩子

    beforeRouteEnter:在进入路由前执行beforeRouteLeave:在离开路由前执行 export default { props: ['id'], name: "UserProfile", beforeRouteEnter: (to, from, next) => { console.log("准备进入个人信息页"); next(); }, beforeRouteLeave: (to, from, next) => { console.log("准备离开个人信息页"); // 当前页面路由的路径 console.log(this.$route.path); next(); } }

    路由钩子中如果不使用next(),路由会一种被钩子劫持不能进行跳转.

    参数说明:

    to:路由将要跳转的路由记录,类型为routefrom:路由跳转前的路由记录,类型为routenext:路由的控制参数 next() 路由继续执行,跳入下一个页面next(’/path’) 改变路由的跳转方向,使其跳到另一个路由next(false) 返回原来的页面next((vm)=>{}) 仅在 beforeRouteEnter 中可用,vm 是组件实例

    Axios异步请求

    安装Axios

    npm install axios -s --registry=https://registry.npm.taobao.org

    main.js中引用Axios

    import axios from 'axios' /*原型链*/ Vue.prototype.axios = axios;

    进行异步请求,要在进入路由前发送请求

    export default { props: ['id'], name: "UserProfile", beforeRouteEnter: (to, from, next) => { console.log("准备进入个人信息页"); // 注意,一定要在 next 中请求,因为该方法调用时 Vue 实例还没有创建,此时无法获取到 this 对象, //在这里使用官方提供的回调函数拿到当前实例,再调用方法 next(vm => { vm.getData(); }); }, methods: { getData: function () { this.axios({ method: 'get', url: 'http://localhost:8080/static/data.json' }).then(function (repos) { console.log('返回结果'+repos); }).catch(function (error) { console.log(error); }); } } } .then(function (repos) { console.log('返回结果'+repos); }) //可使用lambad .then(repos => { console.log('返回结果'+repos); })

    路由懒加载

    当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。

    const Foo = () => import('./Foo.vue') const router = new VueRouter({ routes: [ { path: '/foo', component: Foo } ] })

    打包时每个懒加载的组件会生成一个js文件,用到时按需加载.

    按组分块

    webpackChunkName相同的会打包在一个文件

    const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue') const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue') const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')

    keep-alive结合router-view

    keep-alive可以使被包含的组件保留状态,或避免重新渲染

    <keep-alive> <router-view/> </keep-alive>

    命名视图(一个路由同时渲染多个组件)

    <router-view></router-view> <router-view name="a"></router-view> <router-view name="b"></router-view>

    如果 没有设置名字,那么默认为 default。

    const router = new VueRouter({ routes: [ { path: '/', // 注意多了个 s components: { default: Foo, a: Bar, b: Baz } } ] })
    Processed: 0.010, SQL: 10