vue学习(三)---vue-router路由

    xiaoxiao2022-07-06  208

    1.路由基本结构 2.router-link 3.命名路由 4.路由参数规则 5.重定向和别名 6.$route 和 $router的区别 7.多视图 8.监听路由 9.导航守卫 10. 路由懒加载

    路由基本结构

    1.容器

    <router-view></router-view>

    2.路由表

    let router=new VueRouter({ routes: [ {path, component}, {path, component}, {path, component}, ... ] });

    3.添加到vm对象

    new Vue({ el, data, ..., router: router })
    router-link

    编译完之后就是a标签。主要通过to属性来进行路由跳转

    <router-link class="nav" :to="{name: 'news', params: {id: 98}}">页面1</router-link> <router-link class="nav" to="/b">页面2</router-link> <router-link class="nav" to="/c" tag="div">页面3</router-link>

    tag可以将默认的a标签改为你指定的标签,比如div

    router-link-active 是router-link当前的选中自带class名称,自己可以通过这个class改变成你想要的效果。

    router-link 也是遵守下面的路由参数规则


    命名路由

    对路由设置name属性,为了方便路由的跳转,如果单纯的通过path跳转,一旦path的值过长,或者路由嵌套很深,会显的很乱维护也比较麻烦。 name属性是可选的。

    <router-link class="nav" :to="{name: 'news'}">页面1</router-link> routes: [ { path: '/news', name: 'news', // look at here component: { template: '<div>新闻:{{$route.params.id}}</div>' } }
    命名路由跳转
    //常规 <router-link to="/xxx/xxx"> //命名路由跳转 <router-link class="nav" :to="{name: 'news', params: {id: 98}}">页面1</router-link>
    路由可以重叠

    当多个路由同时匹配到了,那么谁写在最前面就匹配谁的。

    routes: [ { path: '/news/aaa/', component: { template: '<div>新闻2</div>' } }, { path: '/news/:id/', component: { template: '<div>新闻:{{$route.params.id}}</div>' } }

    如果路由输入为/news/aaa 上面的结果会匹配第一个 显示为新闻2。


    路由参数规则

    路由可以通过name,path,params,query来进行参数的传递以及路由的跳转。那么应该如何合理的使用这么参数呢?

    // 字符串 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 会被忽略(因为path是死路经,params是动态路径,query只是路径后的参数),上述例子中的 query 并不属于这种情况。

    所以一般我们写路由的时候可以通过两种方式传参:

    router.push({ path: ‘/register’, query: { plan: ‘private’ }}) (path +query) //register?plan=privaterouter.push({ name: ‘user’, params: { userId: ‘123’ }}) (name+params)// user/123
    重定向和别名
    重定向

    重定向也是通过 routes 配置来完成,下面例子是从 /a 重定向到 /b:

    const router = new VueRouter({ routes: [ { path: '/a', redirect: '/b' } ] })

    重定向的目标也可以是一个命名的路由:

    const router = new VueRouter({ routes: [ { path: '/a', redirect: { name: 'foo' }} ] })

    甚至是一个方法,动态返回重定向目标:

    const router = new VueRouter({ routes: [ { path: '/a', redirect: to => { // 方法接收 目标路由 作为参数 // return 重定向的 字符串路径/路径对象 }} ] })

    注意导航守卫并没有应用在跳转路由上,而仅仅应用在其目标上。在下面这个例子中,为 /a 路由添加一个 beforeEach 或 beforeLeave 守卫并不会有任何效果。

    别名

    “重定向”的意思是,当用户访问 /a时,URL 将会被替换成 /b,然后匹配路由为 /b,那么“别名”又是什么呢?

    /a 的别名是 /b,意味着,当用户访问 /b 时,URL 会保持为 /b,但是路由匹配则为 /a,就像用户访问 /a 一样。

    const router = new VueRouter({ routes: [ { path: '/a', component: A, alias: '/b' } ] })

    “别名”的功能让你可以自由地将 UI 结构映射到任意的 URL,而不是受限于配置的嵌套路由结构。


    $route 和 $router的区别

    当前路由信息:$route

    $route.path :字符串,等于当前路由对象的路径,会被解析为绝对路径,如 “/home/news” 。 $route.params :对象,包含路由中的动态片段和全匹配片段的键值对。 $route.query :对象,包含路由中查询参数的键值对。例如,对于 /home/news/detail/01?favorite=yes ,会得到$route.query.favorite = ‘yes’ 。

    $route.router :路由规则所属的路由器(以及其所属的组件)。 $route.matched :数组,包含当前匹配的路径中所包含的所有片段所对应的配置参数对象。 $route.name :当前路径的名字,如果没有使用具名路径,则名字为空。


    操作路由:$router

    this.$router.push( string|object);

    fn1(){ this.$router.push('/news/19'); string this.$router.replace({name: 'news', params: {id: Math.random()}}); object },

    history其实是一个栈,所以路由需要push/replace来操作这个栈。

    push(string|object) 入栈

    replace(string|object) 替换最后一个历史纪录(当前)

    go(int) 就是前进后退


    多视图
    <div id="div1"> <router-link to="/">首页</router-link> <router-link to="/news">新闻</router-link> <!--1.路由容器--> <router-view name="header"></router-view> <router-view></router-view> <router-view name="footer"></router-view> </div> //components 多个s let router=new VueRouter({ routes: [ { path: '/', name: 'index', components: { default: indexCmp, header: headerCmp, footer: footerCmp } }, { path: '/news', name: 'news', components: { default: newsCmp, header: headerCmp, footer: footerCmp } } ] });
    监听路由

    1.watch 简单——只能看不能干预

    watch: { $route(value, old_value){ console.log(value, old_value); } }

    2.路由守卫 ---- 可以阻止路由的跳转 也能控制。


    导航守卫
    1. 全局守卫 2. 单个路由守卫 3. 组件内守卫

    正如其名,vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的。

    记住参数或查询的改变并不会触发进入/离开的导航守卫。你可以通过观察 $route 对象来应对这些变化,或使用 beforeRouteUpdate 的组件内守卫。

    全局前置守卫

    你可以使用 router.beforeEach 注册一个全局前置守卫:

    const router = new VueRouter({ ... }) router.beforeEach((to, from, next) => { // ... })

    当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中。

    每个守卫方法接收三个参数:

    to: Route: 即将要进入的目标 路由对象

    from: Route: 当前导航正要离开的路由

    next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。

    next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。

    next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。

    next(’/’) 或者 next({ path: ‘/’ }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: true、name: ‘home’ 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。

    next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

    确保要调用 next 方法,否则钩子就不会被 resolved。

    全局后置钩子

    你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身:

    router.afterEach((to, from) => { // ... })
    路由独享的守卫

    你可以在路由配置上直接定义 beforeEnter 守卫:

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

    这些守卫与全局前置守卫的方法参数是一样的。

    组件内的守卫

    最后,你可以在路由组件内直接定义以下路由导航守卫:

    beforeRouteEnterbeforeRouteUpdate (2.2 新增)beforeRouteLeave const Foo = { template: `...`, beforeRouteEnter (to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当守卫执行前,组件实例还没被创建 }, beforeRouteUpdate (to, from, next) { // 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例 `this` }, beforeRouteLeave (to, from, next) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例 `this` } }

    beforeRouteEnter 守卫 不能 访问 this,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。 不过,你可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。

    beforeRouteEnter (to, from, next) { next(vm => { // 通过 `vm` 访问组件实例 }) }

    注意 beforeRouteEnter 是支持给 next 传递回调的唯一守卫。对于 beforeRouteUpdate 和 beforeRouteLeave 来说,this 已经可用了,所以不支持传递回调,因为没有必要了。

    beforeRouteUpdate (to, from, next) { // just use `this` this.name = to.params.name next() }

    这个离开守卫通常用来禁止用户在还未保存修改前突然离开。该导航可以通过 next(false) 来取消。

    beforeRouteLeave (to, from , next) { const answer = window.confirm('Do you really want to leave? you have unsaved changes!') if (answer) { next() } else { next(false) } }
    完整的导航解析流程
    导航被触发。在失活的组件里调用离开守卫。调用全局的 beforeEach 守卫。在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。在路由配置里调用 beforeEnter。解析异步路由组件。在被激活的组件里调用 beforeRouteEnter。调用全局的 beforeResolve 守卫 (2.5+)。导航被确认。调用全局的 afterEach 钩子。触发 DOM 更新。用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。
    整合所有的守卫:

    全局的前置守卫: beforeEach beforeResolve 全局的后置钩子: afterEach (钩子函数 这里没有 next) 路由独享的守卫: beforeEnter 组件内的守卫: beforeRouterEnter、beforeRouterUpdate、beforeRouteLeave


    路由懒加载

    当打包构建应用时,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 } ] }) 可在路由中简写 { path:'/foo', name:'foo', component: () => import('@/components/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 会将任何一个异步模块与相同的块名称组合到相同的异步块中。

    /* webpackChunkName: “group-foo” */ 是打包后文件名称,后面是文件路径。

    ‘./Foo.vue’ 是文件路径。

    (可配置或者不配置)在build目录下找到webpack.prod.conf.js文件,将output修改为

    output: { path: config.build.assetsRoot, filename: utils.assetsPath('js/[name].[chunkhash].js'),//文件格式,文件名.文件哈希 chunkFilename: utils.assetsPath('js/[name].[chunkhash].js')//文件切割后的文件名称。这里的name对应的就是路由中引入文件时候的webpackChunkName }

    还有一种形式: 也是实现懒加载的方法。

    vue-router相关的内容就先介绍到这里了,希望对您有所帮助~。

    最新回复(0)