vue从入门到精通之【vue-router】(八)

253 阅读3分钟

前端路由(vue-router/react-router-dom)

单页面应用& 多页面应用

「SPA(single page application)单页面应用」:一个项目只有一个页面,我们基于路由,控制页面展示不同的片段(或组件),当展示内容改变的时候,页面并不会刷新!!

「MPA(multi page application)多页面应用」:一个项目有很多页面,我们做的是页面之间的跳转,每一次跳转都是打开新的页面(相当于页面刷新了)。

单页面应用的项目:移动端大部分都是(追求原生app的操作 体验)、PC端的管理系统 多页面应用的项目:PC端非管理系统的产品。

基于JS动态绑定的内容(vue框架都是这样处理的),在页面的源代码中是看不到内容的,不利于SEO搜索引擎优化!!想做SEO优化,需要服务器渲染(前后端不分离、「现在主流的服务器渲染SSR:node+vue(nuxt.js)+react(next.js)」)!!

  • 首屏服务器渲染【骨架屏】
  • 其余屏幕还是交给客户端渲染

前端路由的模式

「哈希路由(hash router):监听URL地址后面的hash值」

○ 点击按钮改变url地址栏中的hash值改变,控制#app中的内容改变

「浏览器路由(brower/history router):基于H5中的history api实现的」

○ 可以改变URl地址,但是页面不刷新;

○ 如果手动刷新页面,这个地址不存在,报404;需要服务器支持,如果地址不存在,不要返回404,依然返回主页面。

「区别:」

○ hash路由地址不好看,brower路由好看一些;

○ 实现机制不同

hash路由每次跳转修改的是URL的hash值(页面不刷新),基于监听onhashchange事件,获取最新的hash值,去路由表中,找到对应的组件拿过来渲染;

brower路由每次跳转,修改的是URL地址,(页面不刷新),基于history.pushState事件,根据地址找到对应的组件。

○ brower跳转的路由并不真实存在,所以页面手动刷新,会出现404,此时需要后台服务器的配合【后台:如果地址不存在,返回主页的内容】

vue脚手架基于webpack-dev-server启动服务(开发环境),已经完成了服务器应该对history模式支持的相关操作;但是打包到服务器上(生产环境),没有webpack-dev-server,此时需要服务器基于nginx做相同的配置支持。

vue路由

安装

npm i vue-router

步骤

「创建路由规则表」 src/router/index.js

import Vue from "vue";
import VueRouter from "vue-router";
import routes from "./routes"

Vue.use(VueRouter);

const router = new VueRouter({
 // 设置路由模式:hash、history
 mode"hash",
 // 设置路由的匹配规则
 routes
})
export default router;

src/router/routes.js 管理项目路由表

// 管理项目路由表
import Home from "@/pages/Home.vue";
import Analyse from "@/pages/Analyse.vue";
import Order from "@/pages/Order.vue";

const routes = [{
 path"/",//HASH值(pathname值)
 componentHome//渲染的组件
}, {
 path"/analyse",
 componentAnalyse
}, {
 path"/order",
 componentOrder
}, {//以上都不是,重定向到首页
 path"*",
 redirect"/"
}];
export default routes

main.js注册使用路由表

import router from '@/router';

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

实现路由跳转(改变URL地址或者哈希值)

设定一个容器,可以在指定的位置,把基于路由规则匹配的组件进行渲染

「router-view」

router-view内置组件(路由容器):渲染"基于路由规则匹配的组件"的

当页面刷新或者路由跳转后,vue都会拿URL最新的地址(或hash值)去路由表匹配,把匹配到的组件,放到router-view容器中渲染!

每一次的路由切换都是把上一个渲染的组件释放(销毁beforeDestroy->destroyed),把新匹配的组件进行渲染(beforCreate->created->beforeMonut->mounted)

「router-link to="/"」

router-link内置组件(路由跳转、切换组件)

目的:点击实现路由跳转,基于"to"属性指定跳转地址

页面渲染的时候,会把router-link渲染为A标签

页面刷新或路由切换,都会拿最新的地址(或哈希值)和每一个router-link中to的值(或者path属性值)进行匹配,完全匹配""精准"匹配,会给A标签设置router-link-exact-active router-link-active类;非""精准"匹配,只设置router-link-active类;一点都没匹配,啥样式都不设置。==>我们后期可以基于这个特点,给当前匹配的导航设置选中样式。

页面地址:/order

to的地址:

/ 非精准匹配(包含一个完整的)

■ / 任何地址都包含一个完整的斜杠
■ /home2 VS /home 不算
■ /home/list VS /home 算

/analyse 完全不匹配

/order 精准匹配{一毛一样}

<router-link to="/">首頁</router-link>
<router-link to="/analyse">分析頁</router-link>
<router-link :to="{path:'/order'}">訂單頁</router-link>

vue性能优化方案

路由懒加载

如果在编写路由表的时候,事先导入了所有的组件,根据规则渲染不同的组件,这样最后build的时候,会把所以导入的组件打包到一个JS中,JS文件较大,页面第一次加载请求JS的时间过长,延长了白屏等待的时间。

路由懒加载,依托于ES6中提供的import函数

  • webpack打包的时候,实现代码切割:在路由表中已经导入的组件(一般只导入默认展示的)打包到JS中,其余的组件根据情况,分隔成为一个 或多个JS文件
  • 最开始加载页面的时候,只把主JS文件导入,当路由匹配了某个规则,需要渲染某个组件,再把这个组件所在的JS文件导入进来

route router

当我们在new Vue({})的时候,会给每个组件(vue 实例)注入两个私有属性

● this.$route:存储路由匹配的信息

● this.$router:VueRouter的实例,可以调用

  • VueRouter.prototype上的方法实现路由跳转

● $route

fullPath:完整的路由地址(含问号参数信息)

path:不含问号传参信息

query:以键值对的方式存储了问号传参信息

params:{} 存储的是“路径传参”信息或者“隐式传参”信息

name:路由名字

meta:{} 存储设置的路由元的信息

meached:[...] 记录了路由具体的匹配规则记录

hash: 存储除哈希路由内容外的内容,单独设置的hash值

● $router

私有属性方法

   ■ mode路由模式

公有属性方法

   ■ push 跳转到指定的路由 
         ● --> this.$router.push("/analyse")等同于 router-link to="/analyse"
         ● -->this.$router.push({path:'/analyse',...})
   ■ replace 也是跳转到指定的路由,区别在于,push是新增一条历史记录,而replace 是修改本条记录

   ■ go(n): 以当前历史记录为标准,前进或后退,基于N指定步数  go(-1)后退一步  go(1)前进一步

   ■ back -->go(-1)

   ■ forward-->go(1)

   ■ addRoute addRoutes 动态向路由表中加入新的规则记录(动态路由)

   ■ getRoutes 获取现有的路由表

路由切换/路由跳转的传参方式

路由切换/路由跳转的传参方式:每一次路由切换,想把一些信息传递给下一个组件 A组件跳转到B组件

问号传参

#/xxx?xxx==xxx 【丑&能在地址栏中看到传递的信息】因为在地址栏中有,即使手动刷新B页面,信息还可以获取到

隐式传参

● #/xxx 【地址栏中看不见,从内部把信息传递过去&&需要基于路由名字跳转,基于path跳转不可以】建议大家后期在编写路由表的时候,给每一个路由设置一个唯一的名字-->"命名路由",后期实现路由跳转可以不基于path,基于name也可以跳转(可以隐式传参)

因为传递的信息在地址栏中不存在,所以在B页面刷新,传递的信息都没有了

路径参数

● #/xxx/数据 把需要传递的数据当作路由地址的一部分【常用的方案】 ○ 第一步:设置路由表 :xxx设置动态的规则

○ 第二步:跳转 this.$router.push('/home/customass/100/aa')

○ 第三步:获取 this.$router.params --->{id:100,name:'aa'}

特殊情况:跳转前后是同一个组件

路由切换的时候,要释放上一个组件和即将渲染的下一个组件,是同一个组件,此时这个组件既不会被释放也不会被重新渲染,第一次渲染的逻辑不会触发了,例如:created就不会执行了

● 解决方法1:基于watch监听路由变化,从而做一些事情

watch: {
    $route: {
      hadler() {
        ...
      },
      immediatetrue,//重新渲染组件(第一次渲染逻辑),让监听器的处理也执行
    }
  }

● 解决方法2:computed 把需要依赖的路由由变化而变化的信息,都设置为计算属性

computed: {
    title() {
      let { id } = this.$route.params;
      return id ? "修改客户" : "新增客户";
    },
  }

路由导航守卫

在每一次页面刷新(或者路由跳转),路由进行规则匹配的时候,也会触发一些钩子函数==>导航守卫函数

「完整的导航解析流程 A组件-->B组件」

  1. 释放A组件,触发A组件的beforeRouteLeave 钩子函数。 a. A组件释放,即将开启B组件的路由解析和渲染。
  2. 触发全局前置守卫函数 beforeEach 守卫【写在创建路由出】。
  3. 如果A和B是相同的组件,则会触发组件里 beforeRouteUpdate 守卫 (2.2+)。
  4. 再触发匹配的路由配置的独享守卫 beforeEnter【写在路由表中】。 a. B组件被激活,开始进入到B组件中进行解析。
  5. 触发B组件的 beforeRouteEnter函数。
  6. 触发全局解析守卫函数 beforeResolve 守卫 (2.5+)。
  7. 调用全局后置守卫函数 afterEach 钩子。 真实项目中,我们最常用的是 "全局前置守卫 beforeEach":每一次页面刷新(或路由跳转)、也不论从哪跳到哪,beforeEach一定会触发执行。
  • 一般会在 "全局前置守卫 beforeEach"中 ,做登陆态的校验【只要不是进入登陆页,都需要校验是否登陆,如果登陆了,正常进行后面的步骤;如果没登陆,直接让其返回登录页!】

路由元信息

meta:{} 路由元信息:记录每一个路由表的一些基础信息【自定义】

● this.$route.mate 获取

● 根据每个路由表中的记录的不同的元信息,做不同的事情