Vue 路由入门

231 阅读7分钟

Vue是一个单页面应用程序框架,所有功能都在一个html页面上。内容根据需求按需加载组件,提升性能和开发效率。但是也带来了比较差的SEO(无法根据具体内容提供个性化的SEO)。

问题1: Vue又是如何做到 按需加载 更新页面的呢?

首先,要确定的就是 组件访问路径 之间的对应关系。

问题2: 组件访问路径 的对应关系是如何确定的呢?

这就要来看看我们今天的主题 路由 了。

路由

  • 介绍

路径组件映射 关系。根据这个 映射关系,就可以知道访问的路径 应该 渲染 哪个组件

  • 作用

修改 地址栏路径时,切换显示匹配的组件

  • Vue 官方的路由插件

本文我们由浅入深,先从VueRouter开始着手,了解路由,掌握VueRouter的基本使用。

VueRouter

  • 使用
  1. 下载 VueRouter 模板到项目中。例如:3.6.5版本
npm i vue-router@3.6.5

2、引入 + 注册 + 创建路由对象

// router/index.js文件
import Vue from 'vue'
import Router from 'vue-router' // 引入

Vue.use(Router) // 注册

const router = new Router()

3、注入,将路由对象注入到 new Vue 实例中,建立关联

import router from './router'

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

4、创建需要的组件(views 目录),配置路由规则

const router = new Router({
    routes: [
        {
            path: '/publish-manage',
            component: Layout,
            redirect: '/publish-manage/wechat', // 路由重定向
            meta: { title: '发布管理', icon: 'guide' },
            alwaysShow: true,
            children: [
              {
                path: 'wechat', // 地址栏的路径
                name: 'wechat',
                component: () => import('@/views/publish-manage/wechat-graphic/index'), // 异步引入组件
                meta: { title: '微信图文管理' }
              },
              {
                path: 'weibo',
                name: 'weibo',
                component: () => import('@/views/publish-manage/weibo/index'),
                meta: { title: '微博发布' }
              },
            ]
        }
    ]
})
  • 路由模块:将路由按模块拆分,利于维护。

绝对路径:@ 指代 src目录,可以用于快速引入组件。而不是一层一层./../../的形式往上查找。

  • 路由导航

    • 声明式导航 —— 导航链接

    vue-router 提供一个全局组件 router-link,用于替换 a标签

    • router-link 语法

      <router-link to='/路径值' />

      必须传入 to 属性 来 指定路由路径值

    • router-link 高亮 自动给当前导航添加 两个类名

      router-link-active 模糊匹配(一般用的多)

      router-link-exact-active 精准匹配

    • 跳转传参

      1、传参数:to='/path?参数名=值'

      2、接收参数:$route.query.参数名

    • 动态路由传参

      1、配置动态路由

      {
          path: '/search/:words?', // ? 表示参数可选
          component: Search
      }
      

      2、配置导航链接: to='/path/参数值'

      3、接收参数:$route.params.参数名

  • 路由重定向 redirect

说明

重定向 → 匹配path后,强制跳转 path 路径 到 redirect 指向的路径

语法

{
    path: 匹配路径,
    redirect: 重定向到的路径
}
  • 路由 404

作用:当路径找不到匹配时,给个提示页面。

位置:配在路由最后

语法path: '*'

  • 表示 任意路径,当前面的路由都没有匹配到时,命中这个。从而展示给用户自定义的404页面

路由模式

通过 hashhistory 两种方式实现前端路由,更新视图但不重新请求页面 是前端路由原理的核心之一。

  • 路由的两种模式

    • hash路由:本质是利用URL 中的hash,路径中携带 #

    原理: 监听路由变化(onhashchange事件),只有#后面的地址发生变化,可以在 windows 对象上监听这个事件:

    window.onhashchange = function (e) {
      let hash = location.hash// 通过location对象获取hash地址,地址从#开始  
    }
    // onhashchange 事件在当前url的锚部门(以#开始)
    

    因为 hash 发生变化的 url 都会被浏览器记录下来,从而浏览器的前进后退都可以使用。 hashchange 只能改变 # 后面的 url片段

    • history路由

    history api 给了前端完全的路由history api 可以分为两大部分:切换修改

    注意:history 模式下,可以自由的修改path,但是history 模式最终的路由都体现在 urlpathName 中,这部分是会传到服务器的,因此需要服务端对每一个可能的path值都作相应的映射当刷新时,如果服务端没有相应的响应或者资源,页面就会404

    1、切换历史状态:包括backforwardgo 三个方法

    history.go(-2); // 后退两次
    history.go(2); // 前进两次
    histor.back(); // 后退
    history.forward(); // 前进
    

    2、修改历史状态:包括 pushStatereplaceState两个方法, 这两个方法接受三个参数: stateObj, title, url

    • 两种路由模式的区别

    1、前面的 hashchange 只能修改 # 后面的 Url 片段,而 history,可以通过pushState或者 replaceState设置与当前Url同源的任意Url

    2、history 模式会将Url修改的和正常请求后端的Url一样,如果后端没有配置对应的路由处理,则会返回404错误,当用户刷新页面时,浏览器会向服务器发送请求,所以这个实现需要服务器的支持,需要把所有路由都重定向到根页面。

路由跳转

有两种语法:path路径跳转 和 name命名路由跳转

// 不带参数跳转
this.$router.push('路由路径')
this.$router.push({ path: '路由路径' })

this.$router.push({ name: '路由名' }) // 适合path路径较长的场景
// 例如:路由配置 -> { name: '路由名', path: '路由路径', component: 组件 }

// 带参数跳转

//`path路径`跳转 通过 `query传参`
this.$router.push('路由路径?参数1=参数值1&参数2=参数值2')
this.$router.push({
    path: '/路由路径',
    query: {
        参数1: 参数值1,
        参数2: 参数值2
    }
})
//取参:
      模板中 -> `$route.query.参数名`
      script行为中 -> `this.$route.query.参数名`

//`动态路由`跳转传参
this.$router.push('/路由路径/参数值')
this.$router.push({ path: '/路由路径/参数值' })
// 取参: 
      模板中 -> `$route.params.参数名`
      script行为中 -> `this.$route.params.参数名`
      
//`name命名路由` 跳转传参
this.$router.push({
    path: '路由名',
    query: {
        参数1: 参数值1,
        参数2: 参数值2
    }
})
// 取参: 
      模板中 -> `$route.query.参数名`
      script行为中 -> `this.$route.query.参数名`
      
this.$router.push({  // 只有 name命名路由 跳转有
    path: '路由名',
    params: {
        参数1: 参数值1,
        参数2: 参数值2
    }
})
// 取参: 
      模板中 -> `$route.params.参数名`
      script行为中 -> `this.$route.params.参数名`

this.$router.replace() 路由替换,与 this.$router.push 用法一致。

区别:

this.$router.push() :跳转到指定url路径,并向history栈中添加一个记录
点击回退会返回到上一个页面。

this.$router.replace() :跳转到指定url路径,但是history栈中不会有记录
点击返回会跳转到上上个页面(就是直接替换了的页面)

this.$router.go(n): 向前或向后跳转n个页面,n可为正整数或负整数。正整数 前进,负整数后退

组件缓存keep-alive

问题: 从列表到详情,又返回列表,数据重新加载 → 希望回到原来的位置,不重新加载数据

原因: 路由跳转后,列表组件销毁了,返回回来组件又重建了,所以数据重新加载了。

解决方案: 利用keep-alive将组件缓存下来

1、keep-alive是什么?

keep-aliveVue内置组件,当它 包裹 动态组件 时,会 缓存不活动的组件实例,而不是销毁它们。

keep-alive它自身不会渲染成一个 DOM 元素,也不会出现在父组件链中。

2、keep-alive优点

在组件切换的过程中,把切换出去的组件保留在内存中,防止重新渲染DOM,可以减少加载时间喝及性能消耗,提高用户体验性。

3、keep-alive原理

created 函数调用时将需要缓存的 VNode 节点保存在 this.cache 中/在 render(页面渲染) 时,如果 VNodename 符合缓存条件(可以用 include 以及 exclude 控制),则会从 this.cache 中取出之前缓存的 VNode 进行渲染。

VNode虚拟DOM,其实就是一个JS对象

4、keep-alive使用

参数名描述
include字符串或正则表达式只有名称匹配的组件才会被缓存
exclude字符串或正则表达式任何名称匹配的组件都不会被缓存
max数字最多可以缓存多少组件实例

include/exclude值 是组件中的 name 命名,而不是 路由名

// 缓存 组件名 为 test 的组件
<keep-alive include='test'>
    <router-view />
</keep-alive>

// 缓存 组件名 为 a 或 b 的组件
<keep-alive include='a, b'>
    <router-view />
</keep-alive>

// 使用正则表达式, 需要用v-bind
<keep-alive :include='/a|b/'>
    <router-view />
</keep-alive>

// 动态判断
<keep-alive :include='/a|b/'>
    <router-view />
</keep-alive>

// 与 transition  一起使用
<transition>
    <keep-alive :include='/a|b/'>
        <router-view />
    </keep-alive>
</transition>

// 使用数组, 需要用v-bind
<keep-alive :include='["a", "b"]'>
    <router-view />
</keep-alive>

5、keep-alive触发的生命周期

  • activated 当组件被激活(使用)的时候触发 → 进入这个页面的时候触发
  • deactivated 当组件不被使用的时候触发 → 离开这个页面的时候触发

组件缓存后,就不会执行 createdmounteddestroyed等钩子函数

不同情况钩子函数执行情况:

不同情况钩子函数执行情况:
// 不使用 keep-alive
`beforeRouteEnter``created``mounted``destroyed`

// 使用 keep-alive
`beforeRouteEnter``created``mounted``activated``deactivated`
// 再次进入缓存的页面,
只会触发
`beforeRouteEnter``activated``deactivated``created``mounted`不会再执行。