前端路由

看到这里可能有朋友有疑惑了,前端也有路由吗?这些难道不应该是在后端部分操作的吗?确实是这样,但是现在前后端分离后,加上现在的前端框架的实用性,为的就是均衡前后端的工作量,所以在前端也有了路由,减轻了服务器对这方面的判断,在前端做好路由分发之后,后端就只需要写API接口了,更着重于数据交互,逻辑上的代码编写了

单页面应用

那么,既然有前端路由,每个路由是不是都要单写一个页面呢?不需要的,现在都提倡单页面应用

什么是单页面应用呢

单页面应用,即 single page application ,简称SPA ,所有的路由其实都只在一个页面上完成,这种就叫单页面应用,我们不需要每个路由对应一个页面去编写

为什么要用单页面应用

1.传统的根据路由切换页面,都是立即切换,如果切换的网络资源很多的话,加载需要很久,用户体验很不好,并且写的页面越多,也越不好管理,可能还会有很多重复的代码出现,到后期更新迭代后,页面越来越多,这样会产生更多的资源

2.SPA可以完美解决以上的问题,并且数据切换时只是局部切换,且并不会立即切换,而是在某个合适的时间用ajax异步请求后端的API接口,再加载出数据,这里的【某个合适的时间】是指:因为用户查看网页的时候并不会永远都在切换页面吧?所以在某个刚好的时间切换就行了

单页面应用的原理

原理就是运用了锚点,即html页面上的id属性,因为id用的符号【#】,根据前面的web前端基础开发,相信你已经可以理解了,比如一个页面右边的固定按钮,返回顶部,比如这里淘宝的页面,这个返回顶部的按钮

用的就是【#】,这个就不多介绍了,因为学到vue这里,前面说过的,你得有钱端的基础知识才更容易学。在js里【#】其实是hash值,比如这个例子:

因为js自带有location对象,在我点击登录时,因为用onhashchange监听了hash改变,所以立马可以得到新的hash值,然后按逻辑把数据渲染出来

代码:

  1. <!DOCTYPE html>
  2. <html>
  3.  
  4. <head>
  5. <meta charset="utf-8">
  6. <title></title>
  7.  
  8. <style>
  9.  
  10. </style>
  11. </head>
  12.  
  13. <body>
  14. <a href='#/login'>登录</a>
  15. <a href="#/register">注册</a>
  16. <div id="app">
  17.  
  18. </div>
  19. <!-- <script type="text/javascript" src="./node_modules/vue/dist/vue.min.js"></script> -->
  20. <script>
  21. var point = document.getElementById('app');
  22.  
  23. window.onhashchange = function () {
  24. console.log(location);
  25. switch (location.hash) {
  26. case '#/login':
  27. point.innerHTML = '<h2>登录</h2>'
  28. break;
  29. case '#/register':
  30. point.innerHTML = '<h2>注册</h2>'
  31. break;
  32. default:
  33. break;
  34. }
  35. }
  36. </script>
  37. </body>
  38.  
  39. </html>

原生js的路由控制

总之在单页面应用里,用【#】的意思是当前页面根本就没有跳转,还是当前的页面,只是用了一些机制把数据换掉了而已,这个机制就是vue-router,vue-router其实就是用了这个onhash的原理,不过比js原生的多了很多特性和功能

注:

  • 锚点值即a标签的跳转,hash
  • onhashchange获取url上锚点的改变
  • location.hash指当前的锚点
  • js里也有switch的用法

vue-router

vue-router插件位置:

官方文档传送门:点我

vue-router简介

这里说下,为什么要截图官方的文档,直接去官方文档看不就好了吗对吧,原因是:vue-router更新版本很快,所以文档也会跟着更新,有些知识点可能有些不一样。加上也就不用切换到另一个界面看了再回来看了,我截的图也只是个人觉得需要注意的点

安装vue-router

安装之后当前目录下多了个vue-router文件夹:

引入vue-router包

引入本地包

你可以引入你下载的本地的,真正的使用vue-router是和vue配套一起使用的,所以vue也得引入

引入cdn包

查看控制台如果没报错表示引入成功

引入cdn包代码:

  1. <script type="text/javascript" src='https://unpkg.com/vue-router/dist/vue-router.js'></script>
  2.  
  3. <!-- 或者引入指定的版本 -->
  4. <script type="text/javascript" src='https://unpkg.com/vue-router@2.0.0/dist/vue-router.js'></script>

使用vue-router

使用步骤:

1.引入vue-router插件
2.让根元素Vue载入自定义的VueRouter对象(此对象由vue-route插件提供,插件最后会返回一个VueRouter对象和router-linke和router-view组件),方面后面使用
3.创建、配置一个router对象,里面设定好不同的锚点值对应的路由以及对应好第二步里自定义的VueRoter对象
4.将创建好的router对象挂载到vue实例对象上,直接如上写即可,如果报错什么matched,一定是根元素Vue里没有写入router

5.利用vue-router插件提供的两个全局的组件<router-link>和<router-view>设定好DOM布局,通过<router-link>组件的to属性设定好路由路径,且组件最后会被渲染成a标签,<router-view>给定一个路由组件的出口,用于让VueRouter对象进行数据渲染
6.根据不同的路由,渲染整个页面,最后展示出来

注意:

当使用vue-router时,挂载组件只需要再VueRouter对象里挂载就行了,不需要再在vue实例对象里用components属性挂载了

VueRouter定义路由组件的属性是routes,不是router,定义的url属性用path

定义的url路由不用手动写上【#】,vue-router会自动添加上

以上就是vue-router的简单使用

命名路由

vue的路由也可以命名的,是不是感觉越来越像一门后端语言了,哈哈

注:

使用命名路由,在定义路由组件内部,最好用v-bind绑定,添加一个name属性,值则为你定义的路由名字,必须是字典形式:{name:'名字'}

 

我这里试了下,不用绑定直接使用也可以,以前的版本不行的,现在的貌似可以,具体还有待研究,我使用的版本:vue2.6.9,vue-router3.0.2

代码

  1. <!DOCTYPE html>
  2. <html>
  3.  
  4. <head>
  5. <meta charset="utf-8">
  6. <title></title>
  7.  
  8. <style>
  9.  
  10. </style>
  11. </head>
  12.  
  13. <body>
  14. <div id="app">
  15. </div>
  16. <script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script>
  17. <script type="text/javascript" src="./node_modules/vue-router/dist/vue-router.js"></script>
  18. <script>
  19. Vue.use(VueRouter) // 目前是全局状态,可有可不有
  20. var Vlogin = { template: `<div>登录</div>` }
  21. var Vregister = { template: `<div>注册</div>` }
  22. const router = new VueRouter({
  23. routes: [{
  24. path: '/login',
  25. name:'login',
  26. component: Vlogin },
  27. {
  28. path: '/register',
  29. name:'register',
  30. component: Vregister
  31. }]
  32. })
  33. var Vcom = {
  34. template: `<div>
  35. <router-link :to="{name:'login'}">登录页面</router-link>
  36. <router-link :to="{name:'register'}">注册页面</router-link>
  37. <router-view></router-view></div>`
  38. }
  39. let app = new Vue({
  40. el: '#app',
  41. components: { Vcom },
  42. router,
  43. template: `<Vcom />`
  44. })
  45. </script>
  46. </body>
  47.  
  48. </html>

vue-router 命名路由

默认路由

给默认的路由,因为很多时候打开页面,总要展示一个默认的页面吧,所以如下:给路由组件添加一个 '/',然后指向一个你觉得可以作为默认页面的组件就行

补充一下,在vue-router3.0.1版本中,还有这种写法:

但是由于我目前的是3.0.2,所有效果没出来,并且我感觉没多大用啊,反正都是渲染,直接用官方的就行了,搞些新写法整那么花里胡哨干嘛对吧?

路由重定向

这个跟上面的默认路由很类似,只是用的是redirect属性:


我这里访问页面会自动跳转到登录页面,这种就是路由重定向

代码:

  1. <!DOCTYPE html>
  2. <html>
  3.  
  4. <head>
  5. <meta charset="utf-8">
  6. <title></title>
  7.  
  8. <style>
  9.  
  10. </style>
  11. </head>
  12.  
  13. <body>
  14. <div id="app">
  15. </div>
  16. <script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script>
  17. <script type="text/javascript" src="./node_modules/vue-router/dist/vue-router.js"></script>
  18. <script>
  19. Vue.use(VueRouter) // 目前是全局状态,可有可不有
  20. var Vlogin = {
  21. template: `<div>登录</div>`
  22. }
  23. var Vregister = {
  24. template: `<div>注册</div>`
  25. }
  26. const router = new VueRouter({
  27. routes: [{
  28. path:'/',
  29. redirect:'/login'
  30. },
  31. {
  32. path: '/login',
  33. component: Vlogin
  34. },
  35. {
  36. path: '/register',
  37. component: Vregister
  38. }
  39. ]
  40. })
  41. var Vcom = {
  42. template: `<div>
  43. <router-link to="/login">登录页面</router-link>
  44. <router-link to="/register">注册页面</router-link>
  45. <router-view></router-view>
  46. </div>`
  47. }
  48. let app = new Vue({
  49. el: '#app',
  50. components: {
  51. Vcom
  52. },
  53. router,
  54. template: `<Vcom />`
  55. })
  56. </script>
  57. </body>
  58.  
  59. </html>

路由重定向

带参数的路由

我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。例如,我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染

带参数是什么意思,比如就目前我这个博客园后台编辑页面:

https://i.cnblogs.com/EditPosts.aspx?postid=10570774

其中,【?】后面的postid=10...就是带的参数

除了这种,还有这种:

其中的p/105...就是参数,当然博客园的到底用的什么做的url路由就不得而知了,也与本文无关了。

总之就是这种:xxx/user/userid/1,其中的userid/1就是参数

总结下就是,有以下两种参数,表达的意思都是一样的,是为了找page等于多少的数据

xxx.com/cont?page=2

xxx.com/cont/page/1

那么在实际开发中,肯定会有指定某个参数的访问,这种其实就是查询嘛,查询单个数据,也是非常常见且重要的,来个例子:

(有些图片看着字很小或者又显示不全,你右键查看图片源地址可以看大图的,这个是博客园主题的关系,显示不全)

注意:
  • 用【:】匹配的路由组件,path是这样:/page/:pid,有【/】分割,在匹配时用的params,就可以匹配  /page/1,/page/2,/page/3等等的,浏览器url上显示的是 /page/1
  • 另一种匹配,路由组件中的path没做任何改动,直接在匹配时用的query,就可以匹配  /page?pid=1,/page?pid=2,/page?pid=3等等的,浏览器url显示的是  /page?pid=1

相关具体步骤:

1.重新定义了两个局部组件,其中一个用  /page:pid  ,为什么这么写,这是官方文档里明确说明了的:

2.再在router-link里多给了一个参数,params,在另外一个里添加了query:

params和query都是固定的,不能随意更改,不信你可以改了试试。

<router-link :to="{name:'pagep',params:{pid:1}}">第一页</router-link>   匹配对应前面的  xxx.com/cont/page/1
<router-link :to="{name:'pageq',query:{pid:2}}">第二页</router-link>     匹配对应前面的 xxx.com/cont?page=2

那有没有想过,它这就给个参数(params/query),为什么就可以匹配呢?匹配之后可以拿到那个参数吗?

你可以用this.$router和this.$route查看下 ,为什么是这两个参数呢?因为读源码所得,当引入了vue-router之后,Vue实例化对象就多个两个恶属性,一个是$router,一个是$route

如下,给了一个已创建的生命周期函数,在生命周期里打印了this.$router,发现就是VueRouter对象,里面有相关的属性

再打印this.$route看看,发现用【:】 可以匹配url的参数(比如这里用的 :pid),并且给这个参数加了个键,然后匹配到的参数会进入params参数里去,作为一个字典存在:

为什么要传给params呢?你想想,像这样的匹配,匹配到了之后,需要交给后端处理,那你怎么拿到这个参数并传递给后端呢?没有变量名字你怎么传?是不是需要一个形参啊?所以这里就有个params属性,它对应一个字典,字典key就是定义路由组件时path部分,冒号后面的字段,值就是匹配到的值,比如这里就是:{pid:'1'}。

并且它还有个参数query,但是此时如上图,query还是一个空字典。

也就是说这两个属性 query和params都是路由组件自带的属性,它本来就有的,所以知道为什么前面说在router-link绑定那里不能随意换成其他参数了吧

关于这里,可能你理解起来有点吃力,如果你觉得比较吃力,得多看官方文档,传送门   多试几个例子,我个人感觉它那官方文档对于这里都没说的多清楚

由于我是做Python开发的,因为Python的django框架里就有个路由匹配的参数 path('/page:int<pid>',func),其中的pid就可以类比成这里的pid,所以就很好理解,对这Python不熟悉的请忽略我说的Python这个部分

那么有了用【:】匹配,再看另一个url为/page?pid=2是否能拿到值呢?是否会把参数作为键值交给自己自带的属性query呢:

确实如此:

那假如说我把两个router-link传进的参数不小心写错了,本来是params的写成query,本来是query写成了params,看是否可以拿到呢:

拿是可以拿到,但是参数都进错了归属,这种操作太非主流了,可以是可以,但不建议这么干

代码:

  1. <!DOCTYPE html>
  2. <html>
  3.  
  4. <head>
  5. <meta charset="utf-8">
  6. <title></title>
  7. <script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script>
  8. <script type="text/javascript" src="./node_modules/vue-router/dist/vue-router.js"></script>
  9.  
  10. <style>
  11.  
  12. </style>
  13. </head>
  14.  
  15. <body>
  16. <body>
  17. <div id="app">
  18.  
  19. </div>
  20. <script>
  21. Vue.use(VueRouter) // 目前是全局状态,可有可不有
  22. var Vpagep = {
  23. template: `<div>第一页内容</div>`,
  24. created() {
  25. console.log(this.$route)
  26. },
  27. }
  28. var Vpageq = {
  29. template: `<div>第二页内容</div>`,
  30. created() {
  31. console.log(this.$route)
  32. },
  33.  
  34. }
  35. const router = new VueRouter({
  36. routes: [{
  37. path: '/page/:pid',
  38. name: 'pagep',
  39. component: Vpagep
  40. },
  41. {
  42. path: '/page',
  43. name: 'pageq',
  44. component: Vpageq
  45. }
  46. ]
  47. })
  48. var Vcom = {
  49. template: `<div>
  50. <router-link :to="{name:'pagep',query:{pid:1}}">第一页</router-link>
  51. <router-link :to="{name:'pageq',params:{pid:2}}">第二页</router-link>
  52. <router-view></router-view></div>`
  53. }
  54. let app = new Vue({
  55. el: '#app',
  56. components: {
  57. Vcom
  58. },
  59. router,
  60. template: `<Vcom />`
  61. })
  62. </script>
  63. </body>
  64.  
  65. </html>

带参数的路由

编程式导航

编程式导航,听着那么高端大气,到底什么是编程式导航呢,官方文档解释:

也就是说,编程式导航就是直接使用router实例的push方法,并且其实前面我们用的router-link组件最终其实也是用的这个push方法,换言之我们也可以直接使用这个push方法,自定义,自己编写导航,这就是编程式导航

官网使用案例:

  1. // 字符串
  2. router.push('home')
  3.  
  4. // 对象
  5. router.push({ path: 'home' })
  6.  
  7. // 命名的路由
  8. router.push({ name: 'user', params: { userId: '123' }})
  9.  
  10. // 带查询参数,变成 /register?plan=private
  11. router.push({ path: 'register', query: { plan: 'private' }})

更多的就移步自己研究吧:点我

说了半天好像还是不够深刻对吧?还是看例子:

看懂了吧?说白了就是,利用一个事件,在这个事件里把由router-link组件换成了$router.push(),传进一个字典,字典和之前用的router-link传入的一样即可,这个字典就是name和params(或者是query) 

push这个意思就很明显了,就是把这些参数推进去

代码:

  1. <!DOCTYPE html>
  2. <html>
  3.  
  4. <head>
  5. <meta charset="utf-8">
  6. <title></title>
  7. <script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script>
  8. <script type="text/javascript" src="./node_modules/vue-router/dist/vue-router.js"></script>
  9.  
  10. <style>
  11.  
  12. </style>
  13. </head>
  14.  
  15. <body>
  16. <body>
  17. <div id="app">
  18.  
  19. </div>
  20. <script>
  21. Vue.use(VueRouter) // 目前是全局状态,可有可不有
  22. var Vpagep = {
  23. template: `<div>第一页内容</div>`,
  24. created() {
  25. console.log(this.$route)
  26. },
  27.  
  28. }
  29. var Vpageq = {
  30. template: `<div>第二页内容</div>`,
  31. created() {
  32. console.log(this.$route)
  33. },
  34.  
  35. }
  36. const router = new VueRouter({
  37. routes: [{
  38. path: '/page/:pid',
  39. name: 'pagep',
  40. component: Vpagep
  41. },
  42. {
  43. path: '/page',
  44. name: 'pageq',
  45. component: Vpageq
  46. }
  47. ]
  48. })
  49. var Vcom = {
  50. template: `<div>
  51. <button @click="firstHander">第一页</button>
  52. <button @click="secondHander">第二页</button>
  53. <router-view></router-view>
  54. </div>`,
  55. methods:{
  56. firstHander(){
  57. this.$router.push( {name:'pagep',params:{'pid':1}} )
  58. },
  59. secondHander(){
  60. this.$router.push( {name:'pageq',query:{'pid':2}} )
  61. }
  62. }
  63. }
  64. let app = new Vue({
  65. el: '#app',
  66. components: {
  67. Vcom
  68. },
  69. router,
  70. template: `<Vcom />`
  71. })
  72. </script>
  73. </body>
  74.  
  75. </html>

router-push

嵌套路由

因为路由组件之下,完全还有可能有细分的子路由组件之类的,这样就可以把整个页面切分成很多个模块,每个模块做着不同的分工,所以就需要有嵌套路由这个东西,

然后用法和路由组件是一样的,就不用多说了,直接来个例子说明:

先看这个百度首页,我圈出来的部分:

百度首页和个人中心页面当做路由的根组件,把我圈出来的部分作为子路由嵌套嵌套到个人中心路由组件里:

就是这么简单,反正路由组件该有的都得有就行了

代码:

  1. <!DOCTYPE html>
  2. <html>
  3.  
  4. <head>
  5. <meta charset="utf-8">
  6. <title></title>
  7. <script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script>
  8. <script type="text/javascript" src="./node_modules/vue-router/dist/vue-router.js"></script>
  9.  
  10. <style>
  11.  
  12. </style>
  13. </head>
  14.  
  15. <body>
  16.  
  17. <body>
  18. <div id="app">
  19. </div>
  20. <script>
  21. Vue.use(VueRouter) // 目前是全局状态,可有可不有
  22. var Myfollow = {
  23. template: `<div>我的关注</div>`
  24. }
  25. var Navigate = {
  26. template: `<div>导航</div>`
  27. }
  28. var Story = {
  29. template: `<div>小说</div>`
  30. }
  31. var Commend = {
  32. tepmalte: `<div>推荐</div>`
  33. }
  34. var Person = {
  35. template: `<div>个人主页<br>
  36. <router-link to="/Person/follow">我的关注</router-link>
  37. <router-link to="/Person/navigate">导航</router-link>
  38. <router-link to="/Person/story">小说</router-link>
  39. <router-link to="/Person/commend">推荐</router-link>
  40. <router-view></router-view></div>`
  41. }
  42. var Home = {
  43. tempalte: `<div>百度首页</div>`
  44. }
  45. const router = new VueRouter({
  46. routes: [{
  47. path: '/Person',
  48. component: Person,
  49. children: [{
  50. path: '/Person/follow',
  51. component: Myfollow
  52. },
  53. {
  54. path: '/Person/story',
  55. component: Story
  56. },
  57. {
  58. path: '/Person/commend',
  59. component: Commend
  60. },
  61. {
  62. path: '/Person/navigate',
  63. component: Navigate
  64. },
  65. ]
  66. },
  67. {
  68. path: '/home',
  69. component: Home
  70. }
  71. ]
  72. })
  73. var Root = {
  74. template: `<div>
  75. <router-link to="/home">百度首页</router-link>
  76. <router-link to="/Person">个人主页</router-link>
  77. <router-view></router-view></div>`
  78. }
  79. const app = new Vue({
  80. el: '#app',
  81. router,
  82. components: {
  83. Root,
  84. },
  85. template: `<Root />`,
  86. })
  87. </script>
  88. </body>
  89.  
  90. </html>

嵌套路由

子路由的path

唯一要注意的是,写子路由的path时,要嘛带上完整的路由:

要嘛不要带/,直接给一个路由的相对路径,vue会自动拼写成完整路由,其他没做任何改变,一样可以显示:

动态路由

我画出来的那个【'$route'】这个要注意,后面我们会用到

什么是动态路由呢,我个人觉得官网讲的太随意了, 你看了估计都看不太懂啥意思

那么动态路由到底是什么呢?这么说吧,因为Vue是单页面应用,那么就会有很多公用路由组件部分对吧,那么这些公用组件部分会被多个组件使用,通常的方法就是把公用路由组件挂载成子组件,然后公用的部分显示,不同的部分做单独渲染或者说单独的覆盖数据就行。

这意思感觉有点像是模板一样对吧?反正都是那一套模板,把数据放进去就行了,好的,不多说,直接上例子:

先看个网站,稀土掘金的,这个也是个开发者社区,然后我标记出来的,1就是根路由,2就是子路由,3就是公用部分(这个是要账号登录状态才有的),不管我点2部分的路由的哪个标签,3永远都有的,而且没有变,切换的永远是3下面的数据,并且3下面的数据的css样式也是公用部分:

好的,简单的模仿一个:

(为了在一个页面显示,所以排版看着有点怪)

看下控制台打印的结果:

大概什么逻辑呢?就是相同部分都用同一个路由组件作为子组件,在父级路由的router-link里传入对应的标签参数,在公用路由组件里做下处理,把内容填充上就行,不再需要分别定义多个组件了。

这个在实际开发中,可以再公用路由组件里做判断,如果是哪个子路由,数据就是什么样,做好不同的分类显示就行了,这里作为案例就没做那么详细真实了

好的,至于这个  '$route'(to,form)  其中的'$route'到底是什么暂且不 谈了,详细的看官网了

代码:

  1. <!DOCTYPE html>
  2. <html>
  3.  
  4. <head>
  5. <meta charset="utf-8">
  6. <title></title>
  7. <script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script>
  8. <script type="text/javascript" src="./node_modules/vue-router/dist/vue-router.js"></script>
  9.  
  10. <style>
  11.  
  12. </style>
  13. </head>
  14.  
  15. <body>
  16.  
  17. <body>
  18. <div id="app"></div>
  19. <script>
  20. Vue.use(VueRouter) // 目前是全局状态,可有可不有
  21. var Pins = {
  22. template: ` <div>我是沸点</div>`
  23. }
  24. var common = { // 公用组件
  25. data() {
  26. return {
  27. msg: ''
  28. }
  29. },
  30. template: `<div>公用部分:发表 - 写文章 - 分享链接
  31. <div>{{msg}}</div></div>`,
  32. created() {
  33. this.msg = '(css样式结构,还没有数据)'
  34. },
  35. watch: {
  36. '$route'(to, form) {
  37. console.log(form);
  38. console.log(to);
  39. this.msg = `${this.$route.params.category} 相关内容内容内容.........`
  40. }
  41. }
  42. }
  43. var home = {
  44. template: `<div>
  45. <router-link :to="{name:'common',params:{category:'commend'}}">推荐</router-link>
  46. <router-link :to="{name:'common',params:{category:'follow'}}">关注</router-link>
  47. <router-link :to="{name:'common',params:{category:'android'}}">安卓</router-link>
  48. <router-view></router-view></div>`,
  49. }
  50. // 注意路由挂载组件的先后顺序,先创建再在路由里挂载
  51. const router = new VueRouter({
  52. routes: [{
  53. path: '/home',
  54. component: home,
  55. children: [{
  56. path: '/',
  57. component: common
  58. },
  59. {
  60. path: '/home/:category',
  61. name: 'common',
  62. component: common
  63. }
  64. ]
  65. },
  66. {
  67. path: '/pins',
  68. name: 'pins',
  69. component: Pins
  70. }
  71. ]
  72. })
  73. var com = {
  74. template: `<div>
  75. <router-link to="/home">首页</router-link>
  76. <router-link to="/pins">沸点</router-link>
  77. <router-view></router-view></div>`
  78. }
  79. const app = new Vue({
  80. el: '#app',
  81. components: {
  82. com
  83. },
  84. router,
  85. template: `<com/>`
  86. })
  87. </script>
  88. </body>
  89.  
  90. </html>

动态路由

keep-alive的用法

在路由组件中也可以用keep-alive,主要用途是对切换页面时组件的缓存,防止销毁创建增大开销

这个在前面的局部组件也有用到的,不多说。用法就是在组件的出口前后加一个vue特殊的组件<keep-alive>包裹住即可

其他没变只是在入口函数那里加了keep-alive组件

全局前置守卫验证

 这个全局前置守卫在旧版的vue-router里名字叫全局守卫

在开发中,按照常识,都知道,不同用户的权限是不一样的,然后能访问的路由也是不一样的,所以这就是权限,而作为权限验证,得有一套机制吧,这套机制就是全局守卫

比如,某个网站,验证用户的登录状态,如果未登录就提示登陆,否则就进不了需要登录的网页,必须登录之后才可以查看网页,这种场景就可以用全局前置守卫

相关的说明:

上面这个说的什么意思呢,主要就是说,必须要调用next方法,不然的话会卡住

路由元信息

首先呢,路由组件有一个元信息meta参数,这个参数就可以配置一些权限验证:

这里给一个小demo,如下,这是优酷视频网的某个部分,上面是免费视频,下面是需要会员才能看的视频

好的,就做个这种简单的出来:

点击会员时,它会自动跳转到登录页面

当我登录之后,会员页面显示:

以上部分,在router-link传入参数部分,可能有朋友会想,唉,你这为什么要定义两个公用组件,都那一套啊,免费电影和会员部分都用一套公用组件多省事啊,确实啊,这样确实省事,其实最开始我就是这样的,但是因为都用一个公用组件,在不同根组件切换到子组件时,会有错乱,达不到我们的需要的效果,所以我定义了两个公用组件。并且针对两个组件,后期肯定还会有不同的配置的,所以这样会更好维护一点

原理就是在定义路由时,给需要验证的路由配置原信息,加了个meta参数,这个参数是router对象自带的属性,我们可以随意定义键值进去:

利用这个键值用beforeEach全局守卫在路由跳转时判断这个参数,如果为true则需要做验证,验证通过则next()为空放行,验证不通过则用next跳转,这里的next是个回调函数,有点编程式导航router.push的意思,此时这个beforeEach全局守卫其实也可以看出一个周期钩子函数

对于验证登录状态,用了js自带的一个localStorage永久存储对象作为存储 :

需要清除的话,右键那个那个file://,点clear就行,详细的就不多说了,自行查资料研究吧

完整代码

  1. <!DOCTYPE html>
  2. <html>
  3.  
  4. <head>
  5. <meta charset="utf-8">
  6. <title></title>
  7. <script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script>
  8. <script type="text/javascript" src="./node_modules/vue-router/dist/vue-router.js"></script>
  9.  
  10. <style>
  11. .common{
  12. margin-top: 2%;
  13. width: 60%;
  14. height: 100px;
  15. background: purple;
  16. color: white;
  17. border: 1px solid rgb(144, 143, 143);
  18. text-align: center;
  19. line-height: 50px;
  20. }
  21. .mcommon{
  22. margin-top: 2%;
  23. width: 60%;
  24. height: 100px;
  25. background-color: rgb(9, 78, 108);
  26. color:white;
  27. border: 1px solid rgb(172, 168, 168);
  28. text-align: center;
  29. line-height: 50px;
  30. }
  31. </style>
  32. </head>
  33.  
  34. <body>
  35.  
  36. <body>
  37. <div id="app"></div>
  38. <script>
  39. Vue.use(VueRouter) // 目前是全局状态,可有可不有
  40. var login = {
  41. data() {
  42. return {
  43. name: '',
  44. pwd: ''
  45. }
  46. },
  47. template: `<div>
  48. <input type='text' v-model="name">
  49. <input type='password' v-model='pwd'>
  50. <button @click="loginHander" >登录</button>
  51. </div>`,
  52. methods: {
  53. loginHander() {
  54. localStorage.setItem('user', {
  55. 'name': this.name,
  56. 'pwd': this.pwd
  57. })
  58. this.$router.push({
  59. path: '/member'
  60. })
  61. }
  62. },
  63. }
  64. var common = { // 免费电影公用组件
  65. data() {
  66. return {
  67. msg: ''
  68. }
  69. },
  70. template: `<div class="common">免费电影公用部分:XXXXX
  71. <div>{{msg}}</div></div>`,
  72. created() {
  73. this.msg = '(css样式结构,还没有数据)'
  74. },
  75. watch: {
  76. '$route'(to, form) {
  77. console.log(form);
  78. console.log(to);
  79. this.msg = `${this.$route.params.category} 相关内容内容内容.........`
  80. }
  81. }
  82. }
  83. var mcommon = { // 会员电影公用组件
  84. data() {
  85. return {
  86. msg: ''
  87. }
  88. },
  89. template: `<div class="mcommon">会员电影公用部分:XXXXX
  90. <div>{{msg}}</div></div>`,
  91. created() {
  92. this.msg = '(css样式结构,还没有数据)'
  93. },
  94. watch: {
  95. '$route'(to, form) {
  96. console.log(form);
  97. console.log(to);
  98. this.msg = `${this.$route.params.category} 相关内容内容内容.........`
  99. }
  100. }
  101. }
  102.  
  103. var movie = { // 免费视频
  104. template: `<div>
  105. <router-link :to="{name:'common',params:{category:'hollywood'}}">好莱坞</router-link>
  106. <router-link :to="{name:'common',params:{category:'trailer'}}">预告片</router-link>
  107. <router-link :to="{name:'common',params:{category:'online-movie'}}">网络电影</router-link>
  108. <router-view></router-view></div>`,
  109. }
  110. var member = { // 会员视频
  111. template: `<div>
  112. <router-link :to="{name:'mcommon',params:{category:'lastest'}}">最新</router-link>
  113. <router-link :to="{name:'mcommon',params:{category:'cinema'}}">院线大片</router-link>
  114. <router-link :to="{name:'mcommon',params:{category:'exclusive'}}">独播强挡</router-link>
  115. <router-link :to="{name:'mcommon',params:{category:'popluar'}}">热门纪实</router-link>
  116. <router-link :to="{name:'mcommon',params:{category:'bbc'}}">BBC经典</router-link>
  117. <router-link :to="{name:'mcommon',params:{category:'anime'}}">热血动漫</router-link>
  118. <router-view></router-view></div>`,
  119. };
  120. // 注意路由挂载组件的先后顺序,先创建再在路由里挂载
  121. const router = new VueRouter({
  122. routes: [{
  123. path: '/movie',
  124. component: movie,
  125. children: [{
  126. path: '/',
  127. component: common
  128. },
  129. {
  130. path: '/movie/:category',
  131. name: 'common',
  132. component: common
  133. }
  134. ]
  135. },
  136. {
  137. path: '/member',
  138. component: member,
  139. meta: { // 带有该参数,表示需要认证
  140. auth: true
  141. },
  142. children: [
  143. // 有认证之后不能再加默认路由,因为加了默认路由之后自动跳到根目录,使认证失效
  144. // {
  145. // path: '/',
  146. // component: mcommon
  147. // },
  148. {
  149. path: '/member/:category',
  150. name: 'mcommon',
  151. component: mcommon
  152. }
  153. ]
  154. },
  155. {
  156. path: '/login',
  157. component: login,
  158. name: 'login'
  159. }
  160. ]
  161. })
  162.  
  163. router.beforeEach((to, from, next) => {
  164. // to and from are both route objects. must call `next`.
  165. console.log(from);
  166. console.log(to.meta.auth);
  167. if (to.meta.auth) {
  168. if (localStorage.getItem('user')) {
  169. next()
  170. } else {
  171. next({
  172. path: '/login'
  173. })
  174. }
  175. } else {
  176. next()
  177. }
  178.  
  179. })
  180.  
  181. var com = {
  182. template: `<div>
  183. <router-link to="/movie">电影</router-link>
  184. <router-link to="/member">会员</router-link>
  185. <router-link to="/login">登录</router-link>
  186. <keep-alive>
  187. <router-view></router-view>
  188. </keep-alive></div>`
  189.  
  190. }
  191. const app = new Vue({
  192. el: '#app',
  193. components: {
  194. com
  195. },
  196. router,
  197. template: `<com/>`
  198. })
  199. </script>
  200. </body>
  201.  
  202. </html>

全局前置守卫,配合meta参数

官方文档里其实还有一个路由内部的守卫是这个:beforeEnter,这个就自己研究了

在vue-router的官方文档里,守卫一共有这么多,自己研究了

补充

如果你遇到这样的报错:

检查你的组件,看template参数写对没有

如果遇到路由匹配到了,但是url没有正常显示:

路由组件如下,

编程式导航部分:

coursedetail部分:

页面显示:

这样虽然有显示,但是url不对,原因是参数匹配有误,路由组件用的参数名是courseId,在做编程式导航时用的参数是detailId,我上面已经标注出来了

作如下改动,即可:

页面正常显示:

总结:

vue-router就到这里,我把经常用到的知识点都揉在一起了,篇幅有点长,耐心看吧,其实都挺简单的,只是有些地方稍微注意一下就行

vue(5)—— vue的路由插件—vue-router 常用属性方法的更多相关文章

  1. [ vue ] quasar框架踩坑:在vue文件外导入路由,执行router.push('/')没有效果

    问题描述: 1. 如图所示的项目结构目录, axios.js 文件负责拦截全局请求和回复,我在拦截回复的代码中写了:如果服务器回复了一个401错误,则执行Router.push('/'),但是该方法失 ...

  2. Vue图片懒加载插件 - vue lazyload的简单使用

    Vue module for lazyloading images in your applications. Some of goals of this project worth noting i ...

  3. Vue(三)之前端路由

    01-前端路由 1.前端路由的实现原理 vue+vue-router 主要来做单页面应用(Single Page Application) 为什么我们要做单页面应用? (1)传统的开发方式 url改变 ...

  4. vue生成路由实例, 使用单个vue文件模板生成路由

    一.vue-loader与vue-router配合 $ cnpm install vue-router --save 二.生成vue-webpack模板 $ vue init webpack-simp ...

  5. 转AngularJS路由插件

    AngularJS学习笔记--002--Angular JS路由插件ui.router源码解析 标签: angular源码angularjs 2016-05-04 13:14 916人阅读 评论(0) ...

  6. [Vue 牛刀小试]:第十二章 - 使用 Vue Router 实现 Vue 中的前端路由控制

    一.前言 前端路由是什么?如果你之前从事的是后端的工作,或者虽然有接触前端,但是并没有使用到单页面应用的话,这个概念对你来说还是会很陌生的.那么,为什么会在单页面应用中存在这么一个概念,以及,前端路由 ...

  7. [Vue 牛刀小试]:第十三章 - Vue Router 基础使用再探(命名路由、命名视图、路由传参)

    一.前言 在上一章的学习中,我们简单介绍了前端路由的概念,以及如何在 Vue 中通过使用 Vue Router 来实现我们的前端路由.但是在实际使用中,我们经常会遇到路由传参.或者一个页面是由多个组件 ...

  8. vue学习指南:第十一篇(详细) - Vue的 路由 第一篇 ( router )

    一.路由的配置 路由  vue-router 1. 什么是路由? 路由相当于一个配置对象 路由:就是我们通过不同的url访问不同的内容,通过angular.js 可以实现多视图的单页,现在流行的单页面 ...

  9. 「Vue」起步 - vue-router路由与页面间导航

    vue-router 我们知道路由定义了一系列访问的地址规则,路由引擎根据这些规则匹配找到对应的处理页面,然后将请求转发给页进行处理.可以说所有的后端开发都是这样做的,而前端路由是不存在"请 ...

随机推荐

  1. Java之Spring mvc详解

    文章大纲 一.Spring mvc介绍二.Spring mvc代码实战三.项目源码下载四.参考文章   一.Spring mvc介绍 1. 什么是springmvc   springmvc是sprin ...

  2. AI2(App Inventor 2)离线版服务器网络版

    个人修改包括: 1.后台增加用户批量添加功能         https://gte.fsyz.net/node/1877 2.上传文件限制改为100M ,编译文件限制改为10M      https ...

  3. MongoDB 4.0 开发环境搭建集群

    环境准备 Liunx 服务器一台 以下示例为单机版安装集群, 没有分片 MongoDB 安装 1.下载 MongoDB tgz 安装包: 可以从下载中心下载: https://www.mongodb. ...

  4. 吴恩达机器学习笔记58-协同过滤算法(Collaborative Filtering Algorithm)

    在之前的基于内容的推荐系统中,对于每一部电影,我们都掌握了可用的特征,使用这些特征训练出了每一个用户的参数.相反地,如果我们拥有用户的参数,我们可以学习得出电影的特征. 但是如果我们既没有用户的参数, ...

  5. PHP Iterator迭代对象属性

    foreach用法和之前的数组遍历是一样的,只不过这里遍历的key是属性名,value是属性值.在类外部遍历时,只能遍历到public属性的,因为其它的都是受保护的,类外部不可见. class Har ...

  6. C# 三种打印方式含代码

    一:C#代码直接打印pdf文件(打印质保书pdf文件) 引用: 代码注释很详细了. private void btn_pdf_Click(object sender, RoutedEventArgs ...

  7. 调研pwa和sw

    概述 处于好奇,最近我调研了一下pwa和service worker,有些新的,记录下来,供以后开发时参考,相信对其他人也有用.pwa主要是通过service worker实现的,它主要包括桌面图标, ...

  8. Vue2.0源码阅读笔记(一):选项合并

      Vue本质是上来说是一个函数,在其通过new关键字构造调用时,会完成一系列初始化过程.通过Vue框架进行开发,基本上是通过向Vue函数中传入不同的参数选项来完成的.参数选项往往需要加以合并,主要有 ...

  9. VC6.0打开或添加工程时崩溃的解决方法

    官方解决办法(英文):http://support.microsoft.com/kb/241396/en-us 网友解决(中文):http://blog.163.com/wjatnx@yeah/blo ...

  10. C#语法——委托,架构的血液

    本篇文章主要介绍委托的应用. 委托是大家最常见的语法了,但会用与精通之间的差别是巨大的. 一个程序员如果不能精通委托,那么,他永远无法成为高级程序员. 所以,让我们把委托刻到血液里吧. 这样,你才能称 ...