必背-11.vue-router
什么是vue-router
- vue-router:Vue的路由
- 网址:
多页面/单页面
前端路由有哪些?
- 前端路由(vue-router/react-router-dom)
- 实现SPA(single page application):单页面应用
- 一个项目只有一个页面,我们基于路由,控制页面展示不同的代码片段(或组件),当展示内容改变的时候,页面并不会刷新
-
MPA(multi page application):多页面应用
- 一个项目有很多页面,我们做的是页面之间的跳转【每一次跳转都是打开新的页面(相当于页面刷新了)】
单页面应用和多页面应用的项目?
-
单页面应用的项目:
- 移动端大部分都是(追求原生App的操作体验)
- PC端管理系统。。。
-
多页面应用的项目:
- PC端非管理系统的产品
基于JS动态绑定的内容(vue框架都是这样处理)在页面的源代码中是看不到内容的,不利于SEO搜索引擎优化!想做SEO优化,需要服务器渲染(前后端不分离、现在主流的服务器渲染SSR:nide+vue(nuxt.js)+react(next.js))
- 现在流行的模式:首屏服务器渲染[骨架屏],其余屏幕还是交给客户端渲染
前端路由模式
-
哈希路由(hash router):监听URL地址后面的哈希值
- 样式:
http://www.xxx/com/index.html#home
-
原理:改变url的哈希值不会刷新页面,通过指定的哈希值使用
window.onhashchange
事件来控制更改页面渲染的内容
- 样式:
-
浏览器路由(browser/history router):基于H5中的historyAPI实现的
-
样式:
http://www.xxx.com/home
- 缺点:需要服务器的支持:(当手动刷新的时候,这个页面不存在,不要返回404,依然返回主页面内容)
-
原理:通过
history.pushState()
方法改变网址,页面不会刷新,再通过window.onpopstate
事件监听网址的改变
-
样式:
-
哈希路由和浏览器路由的区别:
- hash路由地址不好看,browser路由不好看
- 实现机制不同:hash路由每次跳转,修改的是URL的hash值(页面不刷新);金婷hashchange事件,获取最新的hash值,去路由规则表中,找到对应的组件拿过来渲染!!
- browser路由每次跳转,修改的是url地址(页面不刷新
history.pushState
);监听popstate
事件,根据最新的地址找到对应的组件渲染!! - browser路由跳转的地址并不真实存在,所以页面手动刷新,会出现404,此时需要服务器的配合[后台:如果访问的地址不存在,返回主页内容]
- vue脚手架基于
webpack-dev-server
启动的服务(开发环境)、已经完成了"服务器应该对history模式的支持"的相关操作;但是打包部署到服务器上(生产环境),没有webpack-dev-server
,需要服务器的支持(有指定的页面)
vue-router使用
-
第一步:安装:
$npm i vue-router
-
第二步:建立路由规则表:创建路由存放的路径以及index.js 和routes.js文件:
-
//创建index.js文件并配置vue-router的模式和路由规则表 //src/router/index.js :作用是创建vue路由实例,并配置路由 import Vue from "vue"; import VueRouter from "vue-router" import routes from './routes' Vue.use(VueRouter) let router=new VueRouter({ //设置路由模式hash、history(默认) mode:"hash", // 设置路由的匹配规则(路由表):从routes.js中导入 routes }); export default router;
-
//src/router/routes.js :作用是单独管理项目的路由表 import Home from '@/pages/Home.vue' import Analyse from '@/pages/Analyse.vue' import HomeRoutes from "@/router/homeRoutes" const routes=[{ path:"/",//HASH值(pathname值) component:Home//渲染的组件 },{ path:"/analyse", component:Analyse, // 二级路由:如果感觉嵌套太乱,可以将二级路由单独拆为一个文件 children:HomeRoutes },{ path:'*',//以上规则都不匹配 redirect:'/'//也可以重定向到首页(也可以渲染一个404组件) }] export default routes
-
-
第三步:将router实例添加为全局Vue实例的私有属性
-
//main.js import Vue from 'vue'; import App from '@/App.vue'; import router from '@/router/index'; let aaa=new Vue({ //router会添加成为aaa实例的私有属性 router,//=>this.$router && this.$route render: h => h(App), }).$mount('#app'); console.log(aaa);
-
-
第四步:实现路由跳转(改变url地址或者哈希值)
-
<template> <div id="app"> <nav class="nav-box"> <!-- router-link 内置组件(路由跳转/路由切换) +点击实现路由跳转,基于“to”属性指定跳转地址 +页面渲染的时候,会把router-link渲染为a标签 +页面刷新或路由切换,都会拿最新的地址(或哈希值)和每一个router-link中to的值(或者path属性值)进行匹配;完全“精准”匹配的会给A标签设置:router-link-exact-active router-link-acive 两个样式名;非精准匹配的只设置: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> </nav> <main class="main-box"> <!-- router-view 内置组件(路由容器) 用来渲染“基于路由规则匹配组件的” : 当页面刷新或者路由跳转后,vue都会拿url最新的地址(或者hash值)去路由表中进行匹配,把匹配到的组件,放到router-view容器中渲染 而每一次的路由切换,都是把上一个渲染的组件释放(或销毁 beforeDestroy destroyed),把新匹配的组件进行渲染(beforeCreate->created->beforeMount->mounted)--> <router-view></router-view> </main> </div> </template>
-
-
第五步:设置一个容器,可以在指定的位置,把基于路由规则匹配的组件进行渲染
- 以上的
<router-view></router-view>
就是我们制定的位置
- 以上的
router-link
-
router-link 内置组件(路由跳转/路由切换)
-
实现页面跳转:点击实现路由跳转,基于“to”属性指定跳转地址
-
<router-link to="/">首页</router-link> <router-link to="/analyse">分析页</router-link> <router-link :to="{ path: '/order' }">订单页</router-link>
-
-
页面渲染的时候,会把router-link渲染为a标签
-
页面刷新或路由切换:都会拿最新的地址(或哈希值)与每一个
router-link
中to属性的值(或者path属性值)进行匹配;完全“精准”匹配的会给A标签设置:router-link-exact-active router-link-acive
两个样式名;非精准匹配的只设置:router-link-active
这个样式类,一点都没匹配的,啥样式都不设置!!=>我们后期可以基于这个特点,给当前匹配的导航设置选中特殊样式
精准匹配/非精准匹配/完全不匹配:
页面地址:/order
to的地址:
/ 非精准匹配 (包含一个完整的)
/ : 任何地址都包含一个完整的斜杠
/home2 VS /home 不算
/home/list VS /home 算
/analyse 完全不匹配
/order 精准匹配(一毛一样)
router-view
-
router-view 内置组件(路由容器):用来渲染“基于路由规则匹配组件的” :
- 当页面刷新或者路由跳转后,vue都会拿url最新的地址(或者hash值)去路由表中进行匹配,把匹配到的组件,放到
router-view
容器中渲染 - 而每一次的路由切换,都是把上一个渲染的组件释放(或销毁
beforeDestroy=>destroyed
),把新匹配的组件进行渲染(beforeCreate->created->beforeMount->mounted)
- 当页面刷新或者路由跳转后,vue都会拿url最新的地址(或者hash值)去路由表中进行匹配,把匹配到的组件,放到
-
用法:
-
<main class="main-box"> <router-view></router-view> </main>
-
二级路由
-
二级路由可以直接在一级路由表中配置,但这样会显得代码嵌套层数太多,我们可以将二级路由抽出来,放在一个js文件中,再进行导入引用:
-
import Home from '@/pages/Home.vue' import HomeRoutes from "@/router/homeRoutes" // 路由根据路由表时自上而下匹配的,只要有一个匹配就直接跳转,所以path:"*"不能在最前面匹配 const routes=[{ path:"/",//HASH值(pathname值) redirect:"/home"//重定向,直接跳转到/home },{ path:"/home", component:Home, // 二级路由:如果感觉嵌套太乱,可以将二级路由单独拆为一个文件 children:HomeRoutes//这里是我们导入的二级路由 },]
-
二级路由homeRoutes.js文件的写法:
-
二级路由也是路由表的形式,只是里面的路径:
- 如果不以斜杠开头,则表示拼接到父级路由后面
- 如果以斜杠开头,则表示井号#后面的全部路径,不会拼接父路由路径
-
// 管理Home板块的路由表 const homeRoutes=[ { path:"",//如果/home后面没有跟路径,则默认将它重定向到'/home/customerlist',也就是让他第一次打开home就在custmerlist页面 redirect:'/home/customerlist' }, { path:"customerlist",//不是斜杠开头,就会拼在一级目录前:=>/home/customerlist component:()=>import("@/pages/home/CustomerList.vue") }, { path:"/home/customeradd",//是斜杠开头,就认为这个路径是绝地路径:=>/home/customeradd component:()=>import("@/pages/home/CustomerAdd.vue") }, { path:"visitList", component:()=>import("@/pages/home/VisitList.vue") } ]; export default homeRoutes;
-
路由懒加载
-
vue性能优化方案之一:路由懒加载
-
问题:如果在编写路由表的时候,事先导入了所有组件,根据规则渲染不同的组件,这样最后build打包的时候,会把所有组件全部打包到一个js中,js文件较大,页面第一次渲染请求js时间过长,延长了白屏事件~~~
-
解决:路由懒加载依托于ES6中提供的import函数
- 1、webpack打包的时候实现代码切割:在路由表中已经导入的组件(一般只导入默认需要展示的,就是第一次访问页面需要展示的),打包到一个js中,其余的组件根据情况,分割为一个或多个js文件!
- 2、最开加载页面,只把主JS文件导入,当路由匹配了某个规则,需要渲染某个组件,再把这个js文件加载
-
-
**写法:**在路由表中各项的component属性后面用ES6函数:
()=>import (/* webpackChunkName: 'analyse'
的形式导入指定路径组件的就是==路由懒加载==-
const routes=[{ path:"/",//HASH值(pathname值) redirect:"/home"//重定向,直接跳转到/home },{ path:"/home", //这是不做路由懒加载的 component:Home, children:HomeRoutes },{ path:"/analyse", //这是做路由懒加载的 component:()=>import (/* webpackChunkName: 'analyse' */"@/pages/Analyse.vue"), }]
-
按组件打包js,按需导入
-
问题:我们每通过
import (/* webpackChunkName: 'analyse'
的形式使组件路由懒加载,都会形成一个单独的js文件,这样就会导致项目中js文件很多。 -
解决:
component:()=>import (/* webpackChunkName: 'analyse' */"@/pages/Analyse.vue"),
- 在import内,最前面加上一句
/* webpackChunkName: 'analyse'*/
这样,它以及它子孙组件就会打包成一个js组件,实现了按包分割的功效,减少了js文件数量
- 在import内,最前面加上一句