| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> JavaScript知识库 -> Vue2.x - Vue Router -> 正文阅读 |
|
[JavaScript知识库]Vue2.x - Vue Router |
目录 ?创建VueRouter实例并将其关联vm.$options.router 通过路由配置属性props简化$route.query的获取 Vue与SPA什么是SPA简单了解SPASPA(Single Page Web Application)单页面网站应用,顾名思义,只有一个网页的网站。 最简单的SPA其实就是,把一个index.html放在网站服务器上,如下 但是这种SPA网站应该不会有人光顾。因为太单调了,太简单了。 而实际上的企业级SPA网站,是要能够基本替代MPA网站,并超越MPA的网站的。 什么是MPAMPA(Multiple Page Web Application)多页面网站应用,顾名思义,由多个网页构成的网站。 目前网络上能访问到的大部分网站都是MPA的。 MPA网站的最大特点就是,从一个网页跳转到另一个网页。 MPA网站的网页间跳转,其实本质是变更浏览器地址栏的URL,促使浏览器刷新网页,来发起HTTP GET请求,到服务器获取到最新的网页资源,这将导致两个问题:
MPA网站还有一些其他的小问题,比如跳转的网页可能会在新页签中打开,这不仅会占用大量浏览器资源,而且会给用户一种混乱的感觉,再比如,每次网页跳转的默认刷新行为都是需要时间的,这段时间会去请求服务器,重新渲染网页等,浪费用户的时间,还有网页刷新会造成网页内容的抖动。 所以MPA的弊端还是挺严重的,但是目前WEB网站,还是MPA模式居多,这是为啥呢? 因为MPA网站开发简单,或者说我们前端开发更熟悉多页面的开发模式。 SPA相较于MPA的优点那么SPA要如何取代MPA,解决MPA的诸多问题呢? 首先我们来谈谈SPA的优点
因为SPA不存在多页面间跳转,只存在单页面中内容切换(局部DOM更新),所以不会导致网页刷新,也就不会发生到服务器请求网页资源的行为,所以SPA内容切换的耗时(请求服务器+渲染)将远远小于MPA网页间跳转的耗时。并且由于没有网页刷新发生,所以也不存在网页抖动。 实现SPA的几个关键点看来SPA无论对于服务器,还是浏览器来说都是友好的嘛! 那么最最最关键的东西来了,SPA如何实现呢? 其实SPA的实现,就是几个关键点的实现:
理解SPA单页面架构我们可以将SPA单页面划分出两个基础区域:导航区、展示区。 比如下图中,我们点击导航区的“用户中心”超链接,就会导致展示区的内容改变(局部DOM更新)为用户中心的内容。 如果是MPA的话,我们点击导航区“用户中心”,则用户中心的内容会以一个独立网页的形式呈现,而不是被更新当前网页的局部。 什么是前端路由什么是路由? 在前端中,路由其实就是:输入在浏览器地址栏的URL? 与? 浏览器窗口呈现的内容(网页或HTML片段)的对应关系。 什么是前端路由,什么是后端路由? 当我们在浏览器地址栏输入URL后,导致网页刷新,促使浏览器发送HTTP GET请求到后端服务器获取对应网页资源。即URL对应的网页来自于后端服务器。此时路由称为后端路由。 当我们在浏览器地址栏输入URL后,不会导致网页刷新,而是触发了浏览器原生的事件,导致对应事件回调会将准备好的HTML片段更新到网页指定位置。即URL对应的HTML片段来自前端自身。此时路由称为前端路由。(PS:SPA网站虽然只有一个网页,但是同时会存在多个HTML片段,这些HTML片段是作为SPA单页面展示区的内容的,一般来说这些HTML片段会和URL组成路由保存在js文件中,然后SPA单页面再引入该js文件即可。) 锚链接与URL中的hash值那么输入什么样的URL,才不会导致网页刷新呢? 之前我们学习a标签时,知道a标签的href支持传入一个锚链接,所谓锚链接就是一个#id,点击超链接就可以将网页首部定位到对应id的标签上。
?通过上面例子我们可以发现, 当我们点击锚链接时,不仅网页首部定位到对应id的标签上,而且浏览器的地址栏的URL也发生了变化,比如 初始时,浏览器地址栏的URL为?
当我们点击锚链接#box2后,浏览器地址栏的URL为?
并且,地址栏URL改变了,并没有导致网页刷新。 ?这是因为URL中#以后的部分(包含#)是URL的hash值,单纯变更URL的hash值,浏览器是不会刷新网页的。这是浏览器内置的一个特性。 ?另外,如果我们强制刷新对应带有hash的URL的网页,浏览器虽然会发送HTTP GET请求到服务器,但是请求URL中不会携带hash值,即服务器不会收到URL的hash值。 ??我们可以通过window.location对象获取到当前地址栏URL的hash值 通过hashchange事件实现前端路由浏览器有一个原生内置事件hashchange,如果当前网页的URL的hash值改变,则会触发hashchange事件,此时我们就可以实现前端路由了
编程式导航目前我们已经根据hashchange事件简单实现了前端路由,但是还有一点美中不足的就是:我们当前只能依赖于a标签锚链接来改变URL中的hash,难道我们所有的导航都要用a标签写吗? 其实我们将a标签锚链接改变URL的hash的方式,叫做“声明式导航”。 除了声明式导航,还有“编程式导航”,编程式导航指的是通过编写代码来改变地址栏中的URL。 基于window.location.hash可读可写属性来实现URL hash的变更 ?可以发现,window.location.hash不仅可以(网页无刷新地)改变地址栏的URL的hash,还可以触发hashchange事件 基于window.history.pushState方法或者replaceState方法实现URL hash的变更 ?可以发现,window.history.pushState方法或者replaceState方法只能(网页无刷新地)改变地址栏的URL值,但是不能触发hashchange事件。 为什么window.history.pushState或replaceState不能触发hashchange事件呢?因为它们改变的是整个URL的值,而不是URL的hash值。 ?下面代码用编程式导航,代替了声明式导航,最终效果一致
浏览器历史记录&前进后退功能我们都知道浏览器有一个历史记录,每当我们在浏览器访问一个网页,该网页的URL就会被记录到浏览器的历史记录中。 那么仅变更了hash的URL会被放入历史记录吗? 通过实践,我们可以发现,无论是a标签锚链接,还是location.hash,还是history.pushState修改了URL的hash后,对应的URL都会被加入历史记录中。 浏览器的历史记录本质是一个栈结构,最早访问的网页的URL存储在栈底,最后访问的网页的URL存储在栈顶。 我们可以利用浏览器的前进、后退菜单键,来调出历史栈中的URL。 而URL入历史栈的方式有两种:
而我们通过?
修改的URL,其实都是以push模式入历史栈。 而只有history.replaceState支持修改的URL以replace模式入历史栈 通过上面例子,我们可以发现历史记录中:hash为#/home的URL?被 hash为#/about的URL覆盖了? Vue与SPA通过Vue认识SPA单页面丰富内容的来源我们基于Vue脚手架打包后的项目,其实就是一个SPA项目,因为打包代码中只有一个index.html。 ?我们来通过Vue创建的SPA项目来验证几个SPA的疑问:
Vue项目打包后的index.html,原始内容非常简单,但是当被浏览器加载后,则会执行其引入的js文件:app.a0561165.js ?在Vue项目中,HTML代码片段是包含在组件模板中的,而组件模板最终都会变转化为虚拟DOM对象 比如上面文件app.a0561165.js就是Vue项目打包后的一个js文件,在该文件中就能找到对应的虚拟DOM对象的痕迹。? 而这里的虚拟DOM对象,最终会被转化为真实DOM对象,插入index.html的指定位置。 这就是SPA网站虽然只有一个网页,但是依旧可以展示大量内容的原因。 在Vue中实现前端路由App.vue
MyAbout.vue
MyHome.vue
怎么说呢,虽然上面代码也可以在Vue项目中实现前端路由,但是非常地不规范,兼容性也很差,所以为了弥补Vue项目的前端路由能力,Vue官方推出了vue-router包。? Vue Router安装和配置Vue Router下载vue-routerVue2.x的项目需要使用vue-router@3 版本的包,Vue3.x的项目需要使用vue-router@4 版本以上的包。 vue-router包需要被Vue项目在生产环境使用 引入vue-router到项目中vue-router对外暴露的VueRouter,不仅是一个构造函数,还是一个Vue插件 注册VueRouter插件注册VueRouter插件,本质是调用其VueRouter构造函数对象的install方法 ?本次注册插件,会带来如下影响: ?创建VueRouter实例并将其关联vm.$options.routerVue构造函数入参配置对象,默认是不支持router属性,但是当我们Vue.use(VueRouter)后,Vue构造函数就被追加处理入参options.router属性的能力了。 路由模块由于Vue Router最终会处理所有的前端路由逻辑,所以安装和配置Vue Router的逻辑写在main.js中,会让main.js变得臃肿,所以Vue官方推荐我们将安装和配置Vue Router的代码写到路由模块 /src/router/index.js中 认识VueRouter路由器和路由VueRouter是一个构造函数,它用于创建一个路由器实例。 路由器的第一个工作就是管理SPA前端路由。 在Vue项目中,前端路由指的是:URL中hash地址 与? 组件 的对应关系。
routes配置属性VueRouter构造函数入参配置对象有一个routes配置属性,它是一个数组,数组元素就是被VueRouter实例管理的前端路由对象。 路由对象有两个基础属性path和component,分别标识 hash地址 和 组件 路由器的第二个工作路由器除了管理路由外,还会时刻监听浏览器地址栏URL的hash地址的变化,一旦hash地址发生改变,则从自身管理的路由中,找到hash地址对应的component组件,并将其渲染到导致hash地址改变的组件中。? 此时有两个问题:
router-link我们知道通过a标签的锚链接可以更改浏览器地址栏中的URL的hash地址,而VueRouter在内部对a标签进行了封装,推出了router-link组件。 router-link组件标签有一个to属性,该属性的值将在router-link标签被点击后,更新为浏览器地址栏URL新的hash地址。 ? 根据实践结果可以发现,router-link标签本质就是一个a标签,router-link的to属性 是对 a标签的href属性的封装。 router-link除了to属性外,还有一个active-class属性,该属性的作用是:为被点击激活的router-link标签添加指定样式(active-class属性值),且具有排他性。 另外router-link组件还有一个tag属性,该属性默认值为'a',表示router-link组件被编译后会变为一个a标签,我们可以自定义tag属性为任何HTML标签,这样最终router-link组件被渲染出来的就是我们指定的HTML标签 router-link组件标签还有一个replace属性,该属性值默认为false,表示router-link标签修改的浏览器地址栏URL后,URL会被以push模式加入浏览器历史记录栈中,而如果设置replace属性为true,则表示URL会被以replace模式加入历史记录栈。 router-viewrouter-view组件用于占位。 当A组件中router-link修改了浏览器地址栏的URL的hash地址后,路由器就会监听到最新的hash地址,并到自身管理路由中,根据hash地址找到对应的路由组件,最终将路由组件渲染到A组件中router-view占位的地方。 认识路由组件什么是路由组件路由中与hash地址对应的组件,就是路由组件。 路由组件与非路由组件最大的区别在于,路由组件不会直接当成组件标签使用,而是完全交给路由器管理。路由器会将路由组件渲染到指定的router-view组件标签占位的地方。 为了在开发过程中,有效区分路由组件和非路由组件,官方推荐将
路由组件的创建和销毁时机路由组件被切入时创建,被切出时销毁。 keep-alive组件keep-alive组件是Vue的内置组件,keep-alive组件可以缓存内容组件的实例,避免组件实例被销毁。 如果我们使用keep-alive组件包裹router-view,则相当于keep-alive组件包裹了路由组件,这样可以缓存路由组件的实例,避免其被切出后销毁。 但是keep-alive默认会缓存所有渲染进router-view的组件,比上面例子中,MyAbout和MyHome组件都会被缓存。 如果我们只想缓存一个指定的组件,则可以使用keep-alive组件标签的include属性的字符串写法? 需要注意,include中写的是组件定义时的name属性值。 如果我们想缓存多个组件的实例,则可以使用include的数组写法? ?keep-alive组件标签还有一个exclude属性,用法和inclue一致,功能相反。 两个新的生命周期钩子actived,deactived由于keep-alive可以缓存其内容组件的实例,导致组件被卸载后,组件的实例不会销毁,而是进入一种失活状态,当组件被重新装载时,组件的实例不会创建,而是直接去激活keep-alive缓存的组件实例。 而keep-alive缓存的组件实例的失活时机,和激活时机,也被加入了钩子。 ?对于路由组件来说,当路由组件被切入时,其actived钩子调用,当路由组件被切出时,其deactived钩子调用。 路由组件实例上的$route属性当我们Vue.use(VueRouter)后,Vue.prototype上就会被挂载一个$route属性,则所有组件实例上就都有了一个$route属性,该属性是一个Object对象,用于收集组件的路由信息。 路由组件上的$router属性?当我们Vue.use(VueRouter)后,Vue.prototype上就会被挂载一个$router属性,则所有组件实例上就都有了一个$router属性,并且所有组件实例的$router都指向了同一个VueRouter实例对象,那就是我们传递给vm.$options.router的路由器对象。路由器对象上主要包含了各种导航方法,用于编程式导航。 嵌套路由什么是嵌套路由??嵌套路由,即子路由
比如下面例子中, 当在App组件中router-link到/home时,App组件中router-view中展示就是Home组件。 当在Home组件中router-link到/home/news时,Home组件中router-view展示的就是News组件。 嵌套路由的实现1、子路由配置属性children VueRouter构造函数入参配置对象的属性:routes数组的元素,就是一级路由。 路由对象都有一个children属性,该属性也是一个数组,用于配置子级路由,例如一级路由对象的children属性中配置的就是二级路由;二级路由对象的children属性中配置的就是三级路由; ?需要注意的是children中路由对象的path是不需要加 / 前缀的,如上,path: 'news',中news并不需要加/前缀,VueRouter内部会为我们自动添加。 ?2、子路由组件的渲染 由于子路由组件,必须要定义在父路由的组件中,比如/home/news就是/home的子路由,所以MyNews组件必然要定义到MyHome组件中,而路由组件都是交给路由器管理的,所以我们只需要在MyHome组件中router-link to /home/news,让路由器找/home/news对应的子组件,然后渲染到router-view中即可 路由重定向 redirect属性在上面例子中,我们发现了一个问题:? ?当hash地址为/home时,其实等价于/home/,即此时子路由为 '' 而/home的子路由中并没有配置 path: ‘’ 的路由,所以没有对应的子组件被渲染,导致MyHome组件的展示区空白。 ?此时,我们可以设置,当路由地址为 /home 时,让其重定向到 /home/news,保证MyHome组件的展示区始终有内容展示。 默认子路由通过路由重定向,我们可以让 /home 和 /home/news 的展示结果一致。 而 /home 又等价于 /home/,所以路由重定向的作用是,让 /home/ 和 /home/news 路由对应同一个路由组件。 相当于: 所以此时,/home/news路由就没有存在必要了,可以简化为 我们将子路由中 path: '' 的路由,称为默认子路由。? 动态路由什么是动态路由在Vue Router中,每一个路由hash地址都要对应一个组件,但是存在一种情况,就是hash地址中存在动态的路径参数
那么此时我们是否需要定义三个组件去分别展示001,002,003呢?如下 虽然可行,但是这种路由定义是有弊端的,如果有001~100的about详情,我们是否要定义100个路由组件呢? 所以Vue Router支持动态路由hash地址。 所谓动态路由hash地址,即将路由hash地址中动态的路径参数用 :参数名 代替,此时动态路由hash地址就可以匹配到 所有复合要求的路由hash了。 $route.params此时我们已经将多个路由hash,对应到了一个路由组件中。 如:/about/001、/about/002、/about/003 都对应路由组件MyDetail。 那么路由组件应该如何获取 动态路由hash地址中动态路径参数呢? 此时我们需要借助 组件实例上的$route属性,该属性是一个对象,包含当前路由组件的所有路由相关信息 我们可以通过 动态路径参数 会挂载为当前路由组件实例身上$route.params对象的属性。 我们需要注意$route.params对象的属性的名字取决于? 定义的动态路径参数名字。 将$route.params转为组件props当前我们需要通过 $route.params.xxx 获取路径参数,形式比较繁琐。所以Vue Router支持将$route.params.xxx 转为 组件的props属性。而组件的props中属性都将挂载为组件实例的直接属性。 为啥可以将$route.params.xxx 当成 props属性?使用呢? 我们其实可以将 父路由组件中 router-link to 导航到 子路由组件的过程,看成是父路由组件给子路由组件传参的过程 ?而to的hash地址中的路径参数,其实就是父路由组件,传递给子路由组件的参数值。 所以这种父子组件传参,子组件通过props配置属性接收,在理论上是合情合理的。 实现props获取动态路由路径参数,我们需要走两步 1、在动态路由中开启props支持,即设置props:true ?2、在动态路由对应的路由组件中,使用props配置属性接收路径参数 路由配置属性props的三种用法前面已经介绍路由配置属性props的第一种用法,即设置路由对象的props属性为true,这样对应路由组件上的$route.params.xxx就会被交给路由组件的props,简化了我们在路由组件中获取动态路由路径参数的形式。 路由配置属性props还有另外两种用法:
我们可以利用路由配置属性props对象 传递一些固定数据给路由组件 ?路由配置属性props还可以写成函数,此时props函数可以接收一个默认入参 $route,该入参就是当前路由组件实例的$route属性 查询参数路由什么是查询参数路由即 路由hash地址中带有查询参数,比如 /home/news?id=001 hash地址中的查询参数不会对hash地址造成影响,即 /home/news 和 /home/news?id=001 都会匹配到 /home下的子路由news。 $route.query其实带有查询参数的路由,也可以看作是一种 父路由组件 向 子路由组件 传参的方式。 在子路由组件中,我们可以通过 组件实例上的$route.query属性获取到查询参数 通过路由配置属性props简化$route.query的获取目前在路由中查询参数的获取,要通过 $route.query.xxx ,形式非常繁琐,此时我们可以通过路由配置属性props来简化其获取形式 我们知道?路由配置属性props 支持三种模式:布尔式、对象式、函数式 其中props函数可以接收到对于路由组件实例的$route属性作为入参,所以 命名路由什么是命名路由简单说,就是给路由配置对象增加一个name属性,即给路由定义一个别名。 如下面例子,给/home/news定义了一个别名xinwen 为什么需要命名路由随着嵌套的路由越来越多,router-link的to属性指向的hash地址也就越来越长,这将使得router-link的to属性的书写非常繁琐。 所以 Vue Router 支持给路由定义别名,让router-link的to属性指向路由的别名? 来替代 冗长的hash地址。 命名路由需要结合router-link组件标签的to属性的对象式写法使用。 router-link to属性的对象式写法router-link to属性的值是一个hash地址,而目前hash地址包括三个部分:
目前,我们都是将这三个部分通过字符串拼接的方式定义在一起的,可读性很差。 所以to属性支持对象式写法,将这三部分作为to对象的属性 ?需要注意的是,如果router-link to的是动态路由,则to对象式写法只能导航到 路由别名,而不能导航到 路由hash地址。因为Vue Router不会将to对象中的path和params组合后进行路由查找,而是直接查找path对应的路由 ?而to对象使用name查找路由的话,则会考虑进params 命名router-view路由配置属性components的对象式写法router-view的作用是占位,当router-link改变了地址栏hash地址后,路由器就会将对应hash地址的路由组件component渲染到router-view中。 但是一个router-view只能渲染一个路由组件,即使我们将router-view定义多次,也只是将一个路由组件渲染多次而已。 所以,为了能够在提供多种路由组件给router-view,可以使用路由配置属性components 命名router-view?路由器根据hash地址找到了对应路由配置对象的components属性,然后路由器会将:
编程式导航什么是导航Vue Router中导航的意思就是改变浏览器地址栏的URL的hash地址,来促使内容切换。 声明式导航
上面这种通过标签点击改变hash地址的方式,称为声明式导航 编程式导航使用代码来改变浏览器地址栏的URL的hash地址 的方式就是编程式导航。 之前介绍SPA路由时,我们尝试了:
来改变hash地址,这些方式就是编程式导航。 而Vue Router对这些方式进行了更加完整的封装,并定义为了 路由器实例 router的方法
编程式导航相较于声明式导航的自由度更高,可以进行异步导航。 router.pushrouter.push有三个入参
router.replacerouter.replace与router.push用法相同,只是在URL存入历史记录栈的方式不同。 router.push是将URL压入栈顶 router.replace是先将栈顶URL出栈,再将replace的URL压入栈顶,表现为替换掉栈顶URL。 router.gorouter.go只有一个入参,入参是一个数值。 该方法是模拟浏览器的前进、后退菜单键功能。 入参正数值,表示前进n个,入参负数值,表示后退n个。 导航守卫什么是导航守卫所谓导航守卫,就是导航拦截。 即,当你访问某hash地址对应的路由组件时,路由器会先拦截你的访问,然后校验你的权限信息,如果权限合法,则放开拦截,让你访问对应路由组件,否则就保持拦截。 为什么需要导航守卫可能大家一听到权限校验相关的东西,下意识决定应该是后端的事情,但是实际企业开发中,基本上所有的校验都要求前后端保持一致。 如果前端未加校验,只在后端加校验,则虽然有后端兜底,不会发生安全问题,但是前端给用户的体验会变差,让用户怀疑网站的安全性。 如果前端加了校验,后端没加校验,则黑客可以绕过前端的校验,直接与后端对话,造成安全问题。 说白了,前端校验就是个样子工程,不做虽然不会导致大问题,但是面子过不去。 所以,前端是需要导航守卫的,虽然是个面子工程。 导航守卫的分类
全局导航前置守卫全局导航前置守卫,就是路由器实例的一个方法beforeEach,该方法接收一个回调函数作为入参。 当导航触发时,beforeEach的参数回调函数就会被调用,底层会依次传入
作为beforeEach的参数回调函数的入参。 下面例子,定义了一个全局导航前置守卫 ?全局导航前置守卫的回调函数执行时机是: 1、项目首次加载时,此时相当于hash地址从 /? 到? / ?2、hash地址发生改变时,如下例中,hash地址从 / 变为 /home/news 关于next函数的四种调用方式next函数是放行函数,它有四种调用方式:
?上面例子分别演示了next放行函数的三种常用用法。 我们需要注意的是,导航守卫中next方法能且只能严格调用一次。
全局导航后置守卫全局导航后置守卫,就是路由器实例的一个方法afterEach,该方法接收一个回调函数作为入参。 当导航结束时,afterEach的参数回调函数就会被调用,底层会依次传入
作为afterEach的参数回调函数的入参 和beforeEach参数回调函数入参不同的是,afterEach的参数回调函数没有next函数,这表明了afterEach并不会起到拦截作用。 afterEach参数回调的调用时机是:
?? 通过上面例子,我们可以发现,
afterEach的作用是,当导航到目标路由后,做一些beforeEach中不好做的统一收尾工作。 比如我们想要变更document.title为当前路由的对应的信息,如果我们在beforeEach中处理的话 可以发现在beforeEach中需要在每次next调用前进行document.title的设置,即需要设置多次,并且要考虑路由跳转中止的话,不能使用to.path作为document.title,只能使用from.path作为document.title。 而在afterEach中,只需要设置一次,且由于afterEach的参数回调只有在路由跳转成功后才会调用,所以可以仅使用to.path作为document.title。 路由元信息属性 meta前面在实现路由校验时,除了要校验用户登录状态,还要校验用户是否有访问对应路由的权限。而当前,我们只能在router.beforeEach中判断各种路由path是否需要权限,此时router.beforeEach中的逻辑非常难看,且后期不容易维护 ?此时我们可以在路由对象中为路由设置元信息,来标记该路由是否需要权限校验 然后在router.beforeEach参数回调中就不需要维护固定path的权限校验了,而是改为统一权限校验 ? 路由独享守卫路由独享守卫 只作用于 当前路由,即当导航到当前路由时,会触发当前路由的独享守卫。 我们可以在路由配置对象中,定义路由独享守卫属性beforeEnter,它是一个函数,底层依次传入
三个入参给beforeEnter。 beforeEnter的调用时机为:当导航到beforeEnter所在路由时,就会触发beforeEnter的执行。 我们可以发现beforeEnter入参的to,永远都是自己所在的路由。? 路由独享守卫,可以做一些路由私有的权限校验。 而如果一个路由,既被路由独享守卫作用,也被全局导航守卫作用,则各守卫执行顺序如下 ?可以发现,执行顺序是:全局导航前置守卫 => 路由独享守卫 => 全局导航后置守卫 组件内守卫组件内路由守卫有三个
而组件内路由守卫,既可以当成导航守卫使用,也可以当成路由组件特有的生命周期钩子使用。 需要注意的是,这三个钩子函数,只有路由组件才有,非路由组件没有。 其实一个组件既可以用作路由组件,也可以用作非路由组件。如下例中,MyLogin既当成了非路由组件使用,又当成了路由组件使用。
其根本原因是,当路由组件是由路由器管理渲染的,而路由器在渲染路由组件的过程中,会调用上面三个钩子。 而非路由组件不是由路由器管理渲染的,所以即使非路由组件定义了上面三个钩子,也没有路由器去调用。? 总结,只有组件被路由器渲染时,才会触发组件的beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave三个钩子。 beforeRouteEnter是在路由组件被渲染之前,即被创建之前调用的,因此此时beforeRouteEnter中是无法访问到组件实例this的。 beforeRouteUpdate?是在路由组件更新时触发的,这里的更新特指:动态路由之间切换时,比如/about/001到/about/002 ?并且,此时beforeRouteUpdate 中可以访问到组件实例。 beforeRouteLeave是在路由组件被卸载之前调用的,即从当前路由 导航到 其他路由前调用 需要注意的是,beforeRouteLeave会在全局导航前置守卫前执行。 beforeRouteLeave可以用来提示用户输入未保存,阻止其跳转到其他路由. 完整的导航解析流程?当一个导航触发后,必然是从一个路由from 跳转到 另一个路由to; 如果from、to都是同一个动态路由,则
如果from、to有一个不是动态路由,则
路由器的两种工作模式hash模式VueRouter的默认工作模式就是hash模式。 而hash工作模式,指的是:路由器通过监听浏览器地址栏中URL的hash地址的变化,来实现前端路由。 此模式的特点是,浏览器地址栏中URL中必定有一个#,如 ?不适合有强迫症的人群。但是此时模式兼容性好。 并且URL中的hash地址仅用于前端路由,不会发送给后端服务器。 histroy模式所谓history模式,即路由器监听的是浏览器地址栏URL的变化,此时URL不需要携带#。 比如 localhost:8080/about 我们可以在定义路由器实例的VueRouter入参配置对象中增加一个属性:mode: 'history' 来开启路由器的history工作模式。 注意观察上面例子中,浏览器地址栏的变化,可以发现此时地址栏URL不再带有#。 这种工作模式的优点是:提升了强迫症患者的视觉感受 但是history模式的缺点却十分致命:
对于第二种缺点,我们可以将Vue项目打包后部署到一个服务器上 ?如上图,我们利用node+express创建一个静态资源托管的服务器,并将SPA项目部署到了服务器静态资源目录,之后启动了服务器。 可以发现,如果我们按照SPA单页面中定义好的导航进行跳转,则没有任何问题。但是当我们刷新网页时,或者通过浏览器地址栏访问某SPA路由时,SPA应用就出错了。 原因很简单,由于是history模式,所以此时前端路由的URL,和后端路由的URL没有任何区别,当我们刷新网页时,或者通过浏览器地址访问某SPA路由时,会触发两种行为:
其中后端路由会失败,因为虽然此时地址栏URL本质还是前端路由,在服务器上并没有对应路由的接口。 比如:localhost/home/news?id=001 当我们刷新网页时,浏览器就会发送一个HTTP GET请求到服务器获取对应资源 此时的解决方案是,让服务器定制对应的前端路由URL对应的接口,然后响应200给前端,让前端不会报错即可。 而express有一个第三方中间件connect-history-api-fallback - npm (npmjs.com) ?就可以帮助后端express服务器自动处理这些前端路由URL。 最终代码案例GitHub - qwx427219/Vue_SPA_Routerhttps://github.com/qwx427219/Vue_SPA_Router.git |
|
JavaScript知识库 最新文章 |
ES6的相关知识点 |
react 函数式组件 & react其他一些总结 |
Vue基础超详细 |
前端JS也可以连点成线(Vue中运用 AntVG6) |
Vue事件处理的基本使用 |
Vue后台项目的记录 (一) |
前后端分离vue跨域,devServer配置proxy代理 |
TypeScript |
初识vuex |
vue项目安装包指令收集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 | -2025/1/11 11:05:00- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |