Vue路由vue-router

概述

前端路由
路由就是根据不同的url地址来展示不同的内容或页面.
Vue Router 是 Vue.js 官方的路由管理器
github: https://github.com/vuejs/vue-router
中文官方网站https://router.vuejs.org/zh/
中文API文档 https://router.vuejs.org/zh/api/

vue-router安装与结构

npm isntall vue-router --save

vue-router是Vue的一个插件,需要在Vue的全局应用中通过Vue.use()将他纳入到Vue实例中
创建项目 router-demo 选择Manually select features

$vue create router-demo

Vue CLI v3.9.2
? Please pick a preset: Manually select features
? Check the features needed for your project:
 ◉ Babel
 ◯ TypeScript
 ◯ Progressive Web App (PWA) Support
❯◉ Router
 ◯ Vuex
 ◯ CSS Pre-processors
 ◉ Linter / Formatter
 ◯ Unit Testing
 ◯ E2E Testing

会在当前项目src目录下自动创建router.js文件

import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/about',
      name: 'about',
      // route level code-splitting
      // this generates a separate chunk (about.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
    }
  ]
})

一条路由的实现需要三部分:
name 名称
path, 路径
component 组件
启动路由器
在main.js 入口文件中启动路由器

Helloworld

接着使用上面的

  1. 创建组件Bar.vue
<template>
    <div >
        <h1>Bar</h1>
        <router-link to="foo">跳转到Foo</router-link>
    </div>
</template>

<script>
    export default {
        name: 'Bar',
    }
</script>

  1. 创建组件Foo.vue
<template>
    <div>
        <h1>Foo</h1>
        <router-link to="bar">跳转到Bar</router-link>
    </div>
</template>

<script>
    export default {
        name: "Foo",
    }
</script>

<style scoped>

</style>
  1. 创建文件router,在其目录下创建index.js文件
import Router from 'vue-router'
import Vue from 'vue'
Vue.use(Router)

import Bar from '../components/Bar'
import Foo from '../components/Foo'

export default new Router({
    routes: [
        {
          path:"/",
          redirect:"/foo"
        },
        {
            path: '/foo',
            component: Foo
        },
        {
            path: '/bar',
            component: Bar
        }
    ]
});

  1. 将App.vue修改
<template>
    <div id="app">
        <img alt="Vue logo" src="./assets/logo.png">
        <router-view></router-view>
        </div>
</template>

<style>
    #app {
        text-align: center;
        margin-top: 60px;
    }
</style>
  1. 在main.js注册路由器
import Vue from 'vue'
import App from './App.vue'
import router from './router/index'

Vue.config.productionTip = false;

new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

动态路由

创建组件User.vue

<template>
    <div>
        {{$route.params.id}}
    </div>
</template>

修改router目录的index文件

import Router from 'vue-router'
import Vue from 'vue'
Vue.use(Router)
import User from  '../components/User'

export default new Router({
    routes: [
        {
            path:'/user/:id',
            component:User
        }
    ]
});

访问的http://localhost:8080/#/user/12347

图片.png

设置“路径参数”,将User.vue 修改成

<template>
    <div>
        {{$route.query.id}}
    </div>
</template>

增加路由配置

        {
            path:'/user',
            component:User
        }

访问路径 http://localhost:8080/#/user?id=2

嵌套路由router-view

创建组件文件Profile.vue

<template>
    <div>
        用户画子界面
    </div>
</template>

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

<style scoped>

</style>

修改路由文件router/index.js

import Router from 'vue-router'
import Vue from 'vue'
Vue.use(Router)
import User from  '../components/User'
import Profile from '../components/Profile'
export default new Router({
    routes: [

        {
            path:'/user',
            component:User,
            children:[
                {
                    path:"profile",
                    component:Profile
                }

            ]
        },
        {
            path:'/user/:id',
            component:User
        }

    ]
});

同一个路径可以匹配多个路由,此时,匹配的优先级就按照路由的定义顺序:谁先定义的,谁的优先级就最高。
访问http://localhost:8080/#/user/profile

图片.png

路由组件传参

方式 1: 路由路径携带参数(param/query)
配置路由

children: [
{
path: 'mdetail/:id',
component: MessageDetail
}
]

路由路径
参数传递 注意需要加上冒号:

<router-link :to="'/home/message/mdetail/'+m.id">{{m.title}}</router-link>

路由组件中读取请求参数,获取传递数据 注意是route 而不是router

this.$route.params.id

方式2 <router-view>属性携带数据

<router-view :msg="msg"></router-view>

缓存路由组件对象

  1. 默认情况下, 被切换的路由组件对象会死亡释放, 再次回来时是重新创建的
  2. 如果可以缓存路由组件对象, 可以提高用户体验
<keep-alive>
<router-view></router-view>
</keep-alive>

路由导航

相关 API

  1. this.$router.push(path): 相当于点击路由链接(可以返回到当前路由界面)
// 字符串
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
  1. this.$router.replace(path): 用新路由替换当前路由(不可以返回到当前路由界面)
  2. this.$router.back(): 请求(返回)上一个记录路由
  3. this.$router.go(-1): 请求(返回)上一个记录路由
  4. this.$router.go(1): 请求下一个记录路由

路由元数据

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

import Router from 'vue-router'
import Vue from 'vue'
Vue.use(Router)
import User from  '../components/User'
import Profile from '../components/Profile'

const router = new Router({
    routes: [
        {
            path:'/user',
            component:User,
            children:[
                {
                    path:"profile",
                    component:Profile
                }
            ]
        },
        {
            path:'/user/:id',
            component:User,
            meta:{
                requireAuth:true
            }
        }

    ]
});

router.beforeEach((to, from, next) => {
    if (to.matched.some(record => record.meta.requireAuth)) {
        next()
    }
})

export default router

路由组件传参

使用route的props进行解耦.提高组件的复用,同时不改变url

修改user.vue组件文件如下

<template>
    <div>
        <p>姓名:{{this.name}}</p>
    </div>
</template>

<script>
    export default {
        name: "User",
        props:["name"]
    }
</script>

<style scoped>

</style>

修改路由文件router/index.js 文件如下

import Router from 'vue-router'
import Vue from 'vue'
Vue.use(Router)
import User from  '../components/User'

const router = new Router({
    routes: [
        {
            path:"/user/profile",
            component:User,
            props:{name:"tony"}
        },
        {
            path:"/user/search",
            component:User,
            props: (route)=>({name:route.query.name})
        },
        {
            path:"/user/:name",
            component:User,
            props:true
        },
    ]
});

function searchName(route){
    return {name:(route.query.name)}
}

export default router

函数返回的是对象类型的 ,props: (route)=>({name:route.query.name}) 等价于

function searchName(route){
    return {name:(route.query.name)}
}

访问接口http://localhost:8081/#/user/search?name=tony
访问接口http://localhost:8081/#/user/profile
访问接口http://localhost:8081/#/user/tony

图片.png

路由懒加载

当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。
结合 Vue 的异步组件和 Webpack 的代码分割功能,轻松实现路由组件的懒加载。
首先,可以将异步组件定义为返回一个 Promise 的工厂函数 (该函数返回的 Promise 应该 resolve 组件本身):

const Foo = () => Promise.resolve({ /* 组件定义对象 */ })

第二,在 Webpack 2 中,我们可以使用动态 import

语法来定义代码分块点 (split point):

import('./Foo.vue') // 返回 Promise

注意
如果您使用的是 Babel,你将需要添加 syntax-dynamic-import

插件,才能使 Babel 可以正确地解析语法。
结合这两者,这就是如何定义一个能够被 Webpack 自动代码分割的异步组件。

const Foo = () => import('./Foo.vue')

在路由配置中什么都不需要改变,只需要像往常一样使用 Foo

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

把组件按组分块

有时候我们想把某个路由下的所有组件都打包在同个异步块 (chunk) 中。只需要使用 命名 chunk

,一个特殊的注释语法来提供 chunk name (需要 Webpack > 2.4)。

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

Webpack 会将任何一个异步模块与相同的块名称组合到相同的异步块中。

组件渲染

在index.html处有个id="app"的div,在App.vue中也有一个id="app"的div。页面渲染的就是这个组件。


图片.png

在这个App.vue中有个router-view标签,默认在这渲染当路由为"/"指向的组件,路由设置在src/router/index.js中

图片.png

这样就可以使用HelloWorld组件了。

图片.png

这张图可以更清楚得让大家明白router-view标签的作用


图片.png

*注意,当有多个组件的时候,就不是component属性而是components,记得注册的组件上面都要用import导入

当组件里有自己的子组件的情况下,就需要使用到router-link标签了,它其实是一个a标签


图片.png

那么router-view和router-link的区别是什么呢?

目前来说,router-link和router-view结合使用,可以在组件中通过点击渲染子组件;
单独使用router-view就可以在当前组件中重根据name属性选择渲染组件;
单独使用router-link就可以整个切换到to属性指定路由的组件;

最后,这个单页面开发的意思就是,这个项目只有index.html这个页面,我们通过使用不同的组件像拼装机器人一样获得不同的页面展示,而src下的App.vue就是所有组件的父组件,所有其它组件都通过路由渲染到它里面的router-view中,然后再将App.vue渲染到index.html中。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,340评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,762评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,329评论 0 329
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,678评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,583评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,995评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,493评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,145评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,293评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,250评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,267评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,973评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,556评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,648评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,873评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,257评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,809评论 2 339

推荐阅读更多精彩内容