vue2-路由

84 阅读9分钟

一. 路由入门

1. 相关理解

1.1 对SPA应用的理解

  1. 单页 Web 应用 SPA(single page web application)
  2. 整个应用只有一个完整的页面
  3. 点击页面中的导航链接不会刷新页面,只会做页面的局部更新
  4. 数据需要通过ajax请求获取。
1.1.1 单页面应用 VS 多页面应用

image.png

image.png

1.1.2 总结
  1. 什么是单页面应用程序?

    所有功能在一个html页面上实现

  2. 单页面应用优缺点?

    优点:按需更新性能高,开发效率高,用户体验好

    缺点:学习成本,首屏加载慢,不利于SEO

  3. 应用场景?

    image.png

1.2 路由的理解

单页面应用程序,之所以开发效率高,性能高,用户体验好,最大的原因就是:页面按需更新

要按需更新,首先就需要明确:访问路径组件的对应关系!

访问路径 和 组件的对应关系如何确定呢? 路由

1.2.1 什么是路由?

image.png

image.png

一个路由(route)就是一组映射关系(key - value),多个路由需要路由器(router)进行管理。

key为路径,value可能是function或component

(前端路由:key是路径,value是组件。)

Vue中路由:路径组件映射 关系,根据路由就能知道不同路径的,应该匹配渲染哪个组件

1.2.2 路由分类
  1. 后端路由

image.png 2. 前端路由

image.png

2. VueRouter 的介绍

Vue 官方的一个路由插件,是一个第三方包,专门用来实现SPA应用

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

2.1 VueRouter 基本使用

5个基础步骤:

  1. 下载:下载 VueRouter 模块到当前工程,命令:npm i vue-router@3

    注意:2022年2月7日以后,vue-router的默认版本为4版本,vue-router4只能在vue3中使用,vue-router3才能在vue2中使用,推荐3.6.5

    Vue2 VueRouter3 vuex3

    Vue3 VueRouter4 vuex4

  2. 引入 import VueRouter from 'vue-router'

  3. 安装注册(应用插件):Vue.use(VueRouter)

  4. 创建路由对象 const router = new VueRouter()

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

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

    通过注入路由器,我们可以在任何组件内通过 this.$router 访问路由器,也可以通过 this.$route 访问当前路由

    router 和 route 的区别

    route 路由,只是一个规则,别人应用这个规则

    router 路由器,有绝对的指挥权,让你去哪就得去哪

2 个核心步骤

  1. 创建组件 (views目录),配置路由规则(路径组件的匹配关系)
    import About from '../components/About'
    import Home from '../components/Home'
    
    const router = new VueRouter({
    	routes:[{
            path:'/about',
            component:About
        },
        {
            path:'/home',
            component:Home
        }]
    })
    
    
  2. 配置导航,配置路由出口 router-view (组件展示的位置)(路径匹配的组件显示的位置)
    <div class="footer_wrap">
       <a href="#/find">发现音乐</a>
       <a href="#/my">我的音乐</a>
       <a href="#/friend">朋友</a>
    </div>
    <div class="top">
       <router-view></router-view>
    </div>
    

2.2 组件存放目录问题

注意:.vue文件 本质无区别。

路由相关的组件,为什么放在 views 目录呢? 组件分类

组件分类: .vue文件分2类; 页面组件 & 复用组件

注意:都是 .vue文件 (本质无区别)

分类开来 更易维护

  • 页面组件 src/views文件夹

    配合路由,页面展示

  • 复用组件 src/components文件夹

    封装复用

2.3 几个注意点

  1. 通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载。

  2. 每个组件都有自己的 $route 属性,里面存储着自己的路由信息。

  3. 整个应用只有一个 router,可以通过组件的 $router 属性获取到。

  4. router 和 route 的区别

    route 路由,只是一个规则,别人应用这个规则

    router 路由器,有绝对的指挥权,让你去哪就得去哪

2.4 多级路由(嵌套路由)

  1. 配置路由规则,使用children配置项:

    routes:[
    	{
    		path:'/about',
    		component:About,
    	},
    	{
    		path:'/home',
    		component:Home,
                //通过children配置子级路由
    		children:[{
                    path:'news', //此处一定不要写:/news
                    component:News
                },
                {
                    path:'message',//此处一定不要写:/message
                    component:Message
                }]
    	}
    ]
    

    注意,以 / 开头的嵌套路径会被当作根路径。 这让你充分的使用嵌套组件而无须设置嵌套的路径。

  2. 跳转(要写完整路径):

    <router-link to="/home/news">News</router-link>
    
  3. 指定展示位置

    <router-view></router-view>
    

二. 路由进阶

1. 路由模块封装

问题:所有的路由配置都堆在main.js中合适么?

目标:将路由模块抽离出来。

路由模块的封装抽离的好处是什么?

  • 拆分模块,利于维护

以后如何快速引入组件?

  • 基于 @ 指代 src 目录,从 src 目录出发找组件
  • 一般放在 @/src/router

2. 声明式导航

2.1 导航链接/导航高亮

router-link是什么?

  • vue-router 提供的全局组件, 用于替换 a 标签

router-link怎么用?

  • <router-link to="/路径值"></router-link>
  • 必须传入to属性, 指定路由路径值

router-link好处?

  • 能跳转,配置 to 属性指定路径(必须) 。本质还是 a 标签 ,to 无需 #
  • 能高亮默认就会提供高亮类名,可以直接设置高亮样式

image.png

2.2 两个类名/精确匹配&模糊匹配

我们发现 router-link 自动给当前导航添加了 两个高亮类名

image.png

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

    to="/my" 可以匹配 /my /my/a /my/b ....

  • router-link-exact-active 精确匹配

    to="/my" 仅可以匹配 /my

2.3 自定义高亮类名

router-link 的 两个高亮类名太长了,我们希望能定制怎么办?

const router = new VueRouter({
    routes: [...],
    linkActiveClass: "类名1",
    linkExactActiveClass: "类名2"
})

image.png

image.png

如何自定义router-link 的 两个高亮类名?

  • linkActiveClass 模糊匹配 类名自定义
  • linkExactActiveClass 精确匹配 类名自定义

2.4 跳转传参

在跳转路由时, 进行传值

  1. 查询参数传参 - query传参

    • 跳转:to="/path?参数名=值" 或 :to={path:路由,query:{参数名:参数值}}
      <!-- to的字符串写法 -->
      <router-link :to="/home/detail?id=666&title=你好">跳转</router-link>
      
      <!-- to的对象写法 path -->
      <router-link 
          :to="{
              path:'/home/detail?id=666&title=你好',
          }"
      >跳转</router-link>
      >
      
      <!-- to的对象写法 path -->
      <router-link 
          :to="{
              path:'/home/message/detail',
              query:{
                 id:666,
                  title:'你好'
              }
          }"
      >跳转</router-link>
      >
      <!-- to的对象写法 name -->
      <router-link 
          :to="{
              name:'xiangqing',
              query: {
                 id:666,
                 title:'你好'
              }
          }"
          >跳转</router-link>
      
    • 获取(对应页面组件接收传递过来的值) $route.query.参数名
  2. 动态路由传参-params参数

    1. 配置动态路由 path: '/search/:words'
    const router = new VueRouter({
        routes: [
            ...,
            {
                path: '/search/:words',
                component: Search
            }
        ]
    })
    
    1. 跳转(配置导航链接) to="/path/参数值"或者对象写法(不常用)

          <!-- 跳转并携带params参数,to的字符串写法 -->
          <router-link :to="/home/message/detail/666/你好">跳转</router-link>
      
          <!-- 跳转并携带params参数,to的对象写法,字符串的复杂化写法 -->
          <router-link 
              :to="{
                 path:'/home/message/detail/666/你好',    
              }"
           >跳转</router-link>
           
          <!-- 跳转并携带params参数,to的对象写法 -->
          <router-link 
              :to="{
                  name:'xiangqing',
                  params: {
                     id:666,
                     title:'你好'
                  }
              }"
          >跳转</router-link>
      

      注意:如果提供了 pathparams 会被忽略,所以路由携带 params 参数时,若使用 to 的对象写法,则不能使用 path 配置项,必须使用 name 配置!

    2. 接收(对应页面组件接收传递过来的值) $route.params.参数名

两种传参方式的区别

  1. 查询参数传参 (比较适合传多个参数)

    ① 跳转:to="/path?参数名=值&参数名2=值"

    ② 获取:$route.query.参数名

  2. 动态路由传参 (优雅简洁,传单个参数比较方便)

    ① 配置动态路由:path: "/path/:参数名"

    ② 跳转:to="/path/参数值"

    ③ 获取:$route.params.参数名

2.5 动态路由参数可选符

/search/:words 表示必须要传参数。如果不传参数,也希望匹配,可以加个可选符 "?" path: '/search/:words?'

const router = new VueRouter({
    routes: [
        ...,
        {
            path: '/search/:words?',
            component: Search
        }
    ]
})

2.6 <router-link>的replace属性

作用:控制路由跳转时操作浏览器历史记录的模式

浏览器的历史记录有两种写入方式:分别为pushreplacepush是追加历史记录,replace是替换当前记录。路由跳转时候默认为push

如何开启replace模式:<router-link replace .......>News</router-link>

3. 路由重定向/404/路由模式

3.1 重定向

问题:网页打开,url 默认是 / 路径,未匹配到组件时,会出现空白

解决:重定向 → 匹配 path后,强制跳转 path 路径

语法: { path: 匹配路径, redirect: 重定向到的路径 },

const router = new VueRouter({
    routes: [
        { path: '/', redirect: '/home'},
        { path: '/home', component: Home },
        {
            path: '/search/:words?',
            component: Search
        }
    ]
})

3.2 404

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

位置:配在路由最后

语法:path: "*" (任意路径) – 前面不匹配就命中最后这个

const router = new VueRouter({
    routes: [
        { path: '/', redirect: '/home'},
        { path: '/home', component: Home },
        {
            path: '/search/:words?',
            component: Search
        },
        {` path: '*', component: NotFind` }
    ]
})

3.3 模式设置

对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值。

hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器。

问题:路由的路径看起来不自然, 有#,能否切成真正路径形式?

路由器的两种工作模式

  • hash路由(默认) 例如: http://localhost:8080/#/home
  • history路由(常用) 例如: http://localhost:8080/home (以后上线需要服务器端支持)
const router = new VueRouter({
    routes,
    //不写mode默认是hash
    mode: "history"
})

两种模式的比较

  • hash模式:

    • 地址中永远带着#号,不美观。
    • 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
    • 兼容性较好。
  • history模式:

    • 地址干净,美观。
    • 兼容性和hash模式相比略差。
    • 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。

4. 编程式导航

问题:点击按钮跳转如何实现?

在 Vue 实例内部,你可以通过 $router 访问路由实例。因此你可以调用 this.$router.push

编程式导航:不借助<router-link>,用JS代码来实现路由跳转,让路由跳转更加灵活

router 和 route 的区别

route 路由,只是一个规则,别人应用这个规则

router 路由器,有绝对的指挥权,让你去哪就得去哪

4.1 基本跳转

两种语法:

  • path 路径跳转(简易方便)

    this.$router.push('路由路径')
    
    this.$router.push({
        path: '路由路径'
    })
    
  • name 命名路由跳转(适合 path 路径长的场景)

    this.$router.push({
        name: '路由名'
    })
    

    注意:使用name命名路由跳转时,定义路由的时候,需要有name { name: '路由名', path: '/path/xxx', component: XXX }

//$router的两个API除了push还有replace
this.$router.push({
    name:'xiangqing',
    params:{
        id:xxx,
        title:xxx
    }
})
this.$router.replace({
    name:'xiangqing',
    params:{
        id:xxx,
        title:xxx
    }
})
this.$router.forward() //前进
this.$router.back() //后退
this.$router.go() //可前进也可后退

4.2 编程式导航传参

问题:点击搜索按钮,跳转需要传参如何实现?

两种传参方式:查询参数 + 动态路由传参

两种跳转方式,对于两种传参方式都支持:

  • path 路径跳转传参
    • query传参

      this.$router.push('/路径?参数名1=参数值1&参数2=参数值2')
      
      this.$router.push({
          path: '/路径?参数名1=参数值1&参数2=参数值2',
      })
      
      //完整写法,更适合传参
      this.$router.push({
          path: '/路径',
          query: {
              参数名1: '参数值1',
              参数名2: '参数值2'
          }
      })
      
      //query传参,接收参数是:$route.query.参数名
      
    • 动态路由传参(需要配动态路由)

      this.$router.push('/路径/参数值')
      
      this.$router.push({
          path: '/路径/参数值'
      })
      

    注意:如果提供了 pathparams 会被忽略

  • name 命名路由跳转传参
    • query传参

      this.$router.push({
          name: '路由名字',
          query: {
              参数名1: '参数值1',
              参数名2: '参数值2'
          }
      })
      
    • 动态路由传参

      this.$router.push({
          name: '路由名字',
          params: {
              参数名: '参数值',
          }
      })
      

4.3 声明式导航和编程式导航

想要导航到不同的 URL,则使用 router.push 方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。

当你点击 <router-link> 时,这个方法会在内部调用,所以说,点击 <router-link :to="..."> 等同于调用 router.push(...)

5. 路由传参 & 路由name

5.1 命名路由 name

作用:可以简化路由的跳转。

如何使用

  1. 给路由命名:

    {
        path:'/demo',
        component:Demo,
        children:[{
            path:'test',
            component:Test,
            children:[{
                name:'hello' //给路由命名
                path:'welcome',
                component:Hello,
            }]
        }]
    }
    
  2. 简化跳转:

    <!--简化前,需要写完整的路径 -->
    <router-link to="/demo/test/welcome">跳转</router-link>
    
    <!--简化后,直接通过名字跳转 -->
    <router-link :to="{name:'hello'}">跳转</router-link>
    
    <!--简化写法配合传递参数 -->
    <router-link 
        :to="{
            name:'hello',
            query:{
               id:666,
                title:'你好'
            }
        }"
    >跳转</router-link>
    

5.2 路由的query参数

  • query传参

    <!-- to的字符串写法 -->
    <router-link :to="/home/detail?id=666&title=你好">跳转</router-link>
    
    <!-- to的对象写法 path,一般参数拼接在地址后面用字符串写法,这种不怎么用,复杂化了,了解即可 -->
    <router-link 
        :to="{
            path:'/home/detail?id=666&title=你好',
        }"
    <!-- to的对象写法 path -->
    <router-link 
        :to="{
            path:'/home/message/detail',
            query:{
               id:666,
                title:'你好'
            }
        }"
    >跳转</router-link>
    
    <!-- to的对象写法 name -->
    <router-link 
        :to="{
            name:'detail',
            query:{
               id:666,
                title:'你好'
            }
        }"
    >跳转</router-link>
    
    
  • 获取(对应页面组件接收传递过来的值) $route.query.参数名

5.3 路由的params参数

  1. 配置路由,声明接收params参数

    {
      path:'/home',
    	component:Home,
    	children:[{
            path:'news',
            component:News
        },{
            component:Message,
            children:[{
                name:'xiangqing',
                path:'detail/:id/:title', //使用占位符声明接收params参数
                component:Detail
            }]
        }]
    }
    
  2. 传递参数

    <!-- 跳转并携带params参数,to的字符串写法 -->
    <router-link :to="/home/message/detail/666/你好">跳转</router-link>
    				
    <!-- 跳转并携带params参数,to的对象写法,一般参数拼接在地址后面用字符串写法,这种不怎么用,复杂化了,了解即可 -->
    <router-link 
    	:to="{
            path:'/home/message/detail/666/你好',
    	}"
    >跳转</router-link>
    
    <!-- 跳转并携带params参数,to的对象写法 -->
    <router-link 
    	:to="{
            name:'xiangqing',
            params:{
               id:666,
               title:'你好'
            }
    	}"
    >跳转</router-link>
    

    注意:如果提供了 pathparams 会被忽略,所以路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!

  3. 接收参数:

    $route.params.id
    $route.params.title
    

5.4 路由传参注意

  • 如果提供了 pathparams 会被忽略

  • 想要导航到不同的 URL,使用 router.push 方法。当点击 <router-link> 时,这个方法会在内部调用,所以说,点击 <router-link :to="..."> 等同于调用 router.push(...)

  • <router-link :to="...">router.push(...)他们传参都是一致的,这一节代码里用的是<router-link>举例,实际换成router.push也可以实现

5.5 路由的props配置

作用:让路由组件更方便的收到参数

{
    name:'xiangqing',
    path:'detail/:id',
    component:Detail,

    //第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
    // props:{a:900}

    //第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件
    // props:true

    //第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
    props($route) {
        return {
          id: $route.query.id,
          title:$route.query.title,
          a: 1,
          b: 'hello'
        }
    }
}

方便在要跳转去的组件里更简便的写法

跳转去组件的具体代码

<template>
  <ul>
      <h1>Detail</h1>
      <li>消息编号:{{id}}</li>
      <li>消息标题:{{title}}</li>
      <li>a:{{a}}</li>
      <li>b:{{b}}</li>
  </ul>
</template>

<script>
export default {
    name: 'Detail',
    props: ['id', 'title', 'a', 'b'],
    mounted () {
        console.log(this.$route);
    }
}
</script>

6. 组件缓存 keep-alive

问题:从面经 点到 详情页,又点返回,数据重新加载了 → 希望回到原来的位置

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

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

6.1 keep-alive是什么

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

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

<template>
    <div class="h5-wrapper">
        <keep-alive>
            <router-view></router-view>
        </keep-alive>
    </div>
</template>

作用:让不展示的路由组件保持挂载,不被销毁。

6.2 keep-alive的优点

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

6.3 keep-alive的三个属性

问题:缓存了所有被切换的组件

keep-alive的三个属性

① include:组件名数组,只有匹配的组件会被缓存

② exclude:组件名数组,任何匹配的组件都不会被缓存

③ max:最多可以缓存多少组件实例

组件名,是组件name的值,如果没有配置name,才会找文件名做为组件名

<!-- 这个 include 指的是组件名 -->
<template>
    <div class="h5-wrapper" :include="['LayoutPage']>
        <keep-alive>
            <router-view></router-view>
        </keep-alive>
    </div>
</template>
<!--缓存一个路由组件 -->
<keep-alive include="News"> 
    <router-view></router-view>
</keep-alive>

<!--缓存多个路由组件 -->
<keep-alive :include="['News','Message']"> 
    <router-view></router-view>
</keep-alive>

6.4 两个生命周期函数

keep-alive的使用会触发的两个生命周期函数

作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。

  • activated 激活时,组件被看到时触发。当组件被激活(使用)的时候触发 → 进入这个页面的时候触发

  • deactivated 失活时,离开页面,组件看不见时触发。当组件不被使用的时候触发 → 离开这个页面的时候触发

组件缓存后就不会执行组件的 created, mounted, destroyed 等钩子了

所以其提供了actived 和 deactived钩子,帮我们实现业务需求。

这两个生命周期钩子需要配合前面的缓存路由组件使用(没有缓存路由组件不起效果)

activated () {
    console.log('actived 激活 → 进入页面');
},

deactivated() {
    console.log('deactived 失活 → 离开页面');
}

6.5 keep-alive 小结

  1. keep-alive是什么

    Vue 的内置组件,包裹动态组件时,可以缓存

  2. keep-alive的优点

    组件切换过程中 把切换出去的组件保留在内存中(提升性能)

  3. keep-alive的三个属性 (了解)

    ① include:组件名数组,只有匹配的组件会被缓存

    ② exclude:组件名数组,任何匹配的组件都不会被缓存

    ③ max:最多可以缓存多少组件实例

  4. keep-alive的使用会触发两个生命周期函数 (了解)

    activated 当组件被激活(使用)的时候触发 → 进入页面触发

    deactivated 当组件不被使用的时候触发 → 离开页面触发

  5. 缓存组件可以用哪个内置组件?

    keep-alive

    三个属性: include exclude max

    两个钩子: activated deactivated

7. 路由守卫

7.1 作用

对路由进行权限控制

7.2 分类

全局守卫、路由独享守卫、组件内守卫

7.3 全局守卫

//全局前置守卫:初始化时执行、每次路由切换前执行
router.beforeEach((to,from,next)=>{
    console.log('beforeEach',to,from)
    if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
        if(localStorage.getItem('school') === 'zhejiang'){ //权限控制的具体规则
            next() //放行
        }else{
            alert('暂无权限查看')
            // next({name:'guanyu'})
        }
    }else{
        next() //放行
    }
})

//全局后置守卫:初始化时执行、每次路由切换后执行
router.afterEach((to,from)=>{
    console.log('afterEach',to,from)
    if(to.meta.title){ 
            document.title = to.meta.title //修改网页的title
    }else{
            document.title = 'vue_test'
    }
})
完整代码
// 这个文件专门用于创建整个应用的路由器
import VueRouter from 'vue-router'
// 引入组件
import About from '../pages/About.vue'
import Home from '../pages/Home.vue'
import Message from '../pages/Message.vue'
import News from '../pages/News.vue'
import Detail from '../pages/Detail.vue'
// 创建并暴露一个路由器
const router = new VueRouter({
    routes: [
        {
            path: '/home',
            component: Home,
            meta:{title:'主页'},
            children: [
                {
                    path: 'news',
                    component: News,
                    meta:{isAuth:true,title:'新闻'}
                },
                {
                    path: 'message',
                    name: 'mess',
                    component: Message,
                    meta:{isAuth:true,title:'消息'},
                    children: [{
                        path: 'detail/:id/:title',
                        name: 'xiangqing',
                        component: Detail,
                        meta:{isAuth:true,title:'详情'},
                        props($route) {
                            return {
                                id: $route.query.id,
                                title:$route.query.title,
                                a: 1,
                                b: 'hello'
                            }
                        }
                    }]
                }
            ]
        },
        {
            path: '/about',
            component: About,
            meta:{ title: '关于' }
        }
    ]
})

// 全局前置路由守卫————初始化的时候被调用、每次路由切换之前被调用
router.beforeEach((to, from, next) => {
    console.log('前置路由守卫', to, from);
    if(to.meta.isAuth) {
        if(localStorage.getItem('school') === 'zhejiang') {
            // 放行
            next()
        } else {
            alert('学校名不对,无权查看')
        }
    } else {
        next()
    }
})

// 全局后置路由守卫————初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to, from) => {
    console.log('后置路由守卫', to, from)
    document.title = to.meta.title || '我的系统'
})

export default router

7.4 路由独享守卫

就是在 routes 子路由内写守卫

beforeEnter(to,from,next){
    console.log('beforeEnter',to,from)
    if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
        if(localStorage.getItem('school') === 'atguigu'){
            next()
        }else{
            alert('暂无权限查看')
            // next({name:'guanyu'})
        }
    }else{
        next()
    }
}

在这里插入图片描述

7.5 组件内守卫

在具体组件内写守卫

//进入守卫:通过路由规则,进入该组件时被调用
beforeRouteEnter (to, from, next) {
},
//离开守卫:通过路由规则,离开该组件时被调用
beforeRouteLeave (to, from, next) {
}

在这里插入图片描述

8. 路由底层 history

你也许注意到 router.push、 router.replace 和 router.go 跟 window.history.pushState、 window.history.replaceState 和 window.history.go (opens new window)好像, 实际上它们确实是效仿 window.history API 的。

因此,如果你已经熟悉 Browser History APIs (opens new window),那么在 Vue Router 中操作 history 就是超级简单的。

9. 基于 VueCli 自定义创建项目

image.png

image.png image.png image.png

9.1 ESlint 代码规范

认识代码规范

代码规范:一套写代码的约定规则。例如:"赋值符号的左右是否需要空格" "一句结束是否是要加;" ...

老话说:"没有规矩不成方圆" → 正规的团队 需要 统一的编码风格

JavaScript Standard Style 规范说明 standardjs.com/rules-zhcn.…

下面是这份规则中的一小部分:

  • 字符串使用单引号 'abc'
  • 无分号 const name = 'zs'
  • 关键字后加空格 if (name = 'ls') { ... }
  • 函数名后加空格 function name (arg) { ... }
  • 坚持使用全等 === 摒弃 ==
  • ...
9.1.1 代码规范错误

如果你的代码不符合 standard 的要求,ESlint 会跳出来刀子嘴,豆腐心地提示你。

比如:在main.js中随意做一些改动,添加一些分号,空行。

image.png

两种解决方案:

  • 手动修正

    根据错误提示来一项一项手动修改纠正。

    如果你不认识命令行中的语法报错是什么意思,根据错误代码去 [[ESLint 规则表]](https://zh-hans.eslint.org/docs/latest/rules/) 中查找其具体含义。

  • 自动修正

    基于 vscode 插件 ESLint 高亮错误,并通过配置 自动 帮助我们修复错误。

    • vscode安装ESLint
    • 配置: image.png 增加以下配置内容
      //当保存到时候,eslint自动帮我们修复错误
      "editor.codeActionsOnSave": {
          "source.fixAll": true
        },
        //保存代码,不自动格式化
        "editor.formatOnSave": false
      

10. 面试常见问题

10.1 vue-router 是干什么的,原理是什么?

vue-router 是 Vue.js 官方的路由插件,它和 vue.js 是深度集成的,适合用于构建单页面应用。vue 的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。传统的页面应用,是用一些超链接来实现页面切换和跳转的。在 vue-router 单页面应用中,则是路径之间的切换,也就是组件的切换。路由模块的本质 就是建立起 url 和页面之间的映射关系。

“更新视图但不重新请求页面”是前端路由原理的核心之一,目前在浏览器环境中这一功能的实现主要有两种方式:

  • 利用 URL 中的 hash(“#”)

    这种方式主要利用了浏览器对 hash 的天然支持,url 中hash 值的改变,不会重新加载页面,也就是说 URL 的 hash 永远不会发送到服务器,因此它不会被包含在 HTTP 请求中。这使得它非常适合用来做前端路由,而不需要服务器端的任何配置。

    通过 window.onhashchange(hashchange事件) 的监听, 匹配不同的url路径,进行解析,加载不同的组件,然后动态的渲染出区域内的html内容。

    注意:事件 hashchange 只会在 hash 发生变化时才能触发,而第一次加载页面时并不会触发这个事件,因此还需要监听 load 事件

  • 利用 History interface 在 HTML5 中新增的 pushState() 和replaceState() 方法。需要特定浏览器支持
    history模式,会出现404 的情况,需要后台配置。