路由

237 阅读5分钟

1.​问题背景:

​vue-router 默认是hash模式,使用url的hash来模拟一个完整的url,当url改变的时候,页面不会重新加 载。但是如果我们不想hash这种以#号结尾的路径时候的话,我们可以使用路由的history的模式。比如如 下网址:使用hash模式的话,那么访问变成 http://localhost:8080/bank/page/count/#/ 这样的访问,

​ 如果路由使用 history的话,那么访问的路径变成 如下:http://localhost:8080/bank/page/count 这样的 了;不过history的这种模式需要后台配置支持。比如:当我们进行项目的主页的时候,一切正常,可以访 问,但是当我们刷新页面或者直接访问路径的时候就会返回404,那是因为在history模式下,只是动态的通过js操作window.history来改变浏览器地址栏里的路径,并没有发起http请求,但是当我直接在浏览器里输入这 个地址的时候,就一定要对服务器发起http请求,但是这个目标在服务器上又不存在,所以会返回404怎么解 决呢?我们现在可以把所有请求都转发到 http://localhost:8080/bank/page/index.html上就可以了

解决方案一:在nginx的配置文件中修改
```php
location /{
   root   /data/nginx/html;

   index  index.html index.htm;

   if (!-e $request_filename) {

       rewrite ^/(.*) /index.html last;

       break;

   }

}
 ```
 
 
解决方案二:vue.js官方教程里提到的

```javascript
 server {

     listen       8081;#默认端口是80,如果端口没被占用可以不用修改

     server_name  myapp.com;

     root        D:/vue/my_app/dist;#vue项目的打包后的dist

     location / {

         try_files $uri $uri/ @router;#需要指向下面的@router否则会出现vue的路由在nginx中刷新出现404

         index  index.html index.htm;

     }

     #对应上面的@router,主要原因是路由的路径资源并不是一个真实的路径,所以无法找到具体的文件

     #因此需要rewrite到index.html中,然后交给路由在处理请求资源

     location @router {

         rewrite ^.*$ /index.html last;

     }

     #.......其他部分省略

}
 ``` 

2.子组件能不能修改父组件传递过来的数据*

   原因:
   在 Vue 中,父子组件的关系可以总结为 prop 向下传递,事件向上传递。父组件通过 prop
   给子组件下发数据,子组件通过事件给父组件发送消息。Prop
   是单向绑定的:当父组件的属性变化时,将传导给子组件,但是反过来不会。这是为了防止子
   组件无意间修改了父组件的状态,来避免应用的数据流变得难以理解

   解决办法:
   将要更改的值,传递给父组件,在父组件中更改,再传递给子组件

   步骤:
   先将值传递给子组件,子组件 props 接收并使用,然后通过 $emit
   广播一个事件给父组件,并将值一并传递,父组件
   @子组件广播过来的事件,并定义一个方法,在该方法中,改变传递过来的值,父组件又会将
   值传递给子组件,这样就形成了一个闭环,问题得以解决

3.路由导航守卫

1.概念

 vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。通俗点讲就是一个拦截器。

2.分类

 全局守卫
 beforeEach、beforeResolve、afterEach(在路由实例对象注册使用)

 路由守卫
 beforeEnter(在路由配置项中项定义)

 组件守卫
 beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave(在组件属性中定义)

钩子的参数
 to: Route: 即将要进入的目标 路由对象
 from: Route: 当前导航正要离开的路由
 next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
 next(false)===不写 终止执行
 next()===next(true)继续执行
 next(path)跳转到目标路径
 
全局守卫详解 在路由的index.js页面设置

 全局前置守卫(beforeEach)

 ```javascript
 // 全局前置守卫 确保要调用 next 方法,否则钩子就不会被 resolved。
 router.beforeEach((to, from, next) => {
     var username = 'miofly'
     if (username === 'miofly') { // 用户是miofly才进入下一个页面
         console.log('beforeEach全局前置守卫被调用')
         next() // 进行管道中的下一个钩子,必须调用
     } else { // 如果不是回到主页
         // 如果直接写next('/indexs'),会造成死循环(dead loop)
         // 这是因为,执行next('/indexs')这个跳转,会触发beforeEach方法,
         // 这时候,就会造成,又执行next('/indexs')  这样的死循环,所以还要再加一层判断
         if (to.path === '/indexs') {
             next()
         } else {
             next('/indexs')
         }
     }
 })
 
 ```

 全局解析守卫(beforeResolve)

 ```javascript
 // 全局解析守卫
 // 和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。
 router.beforeResolve((to, from, next) => {
     console.log('beforeResolve全局解析守卫被调用')
     next()
 })
 ```

 全局后置钩子(afterEach)

 ```javascript
 // 全局后置钩子
 2.	// 可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身:
 3.	router.afterEach((to, from) => {
 4.	    console.log('afterEach全局后置钩子被调用')
 5.	})
 ```

单个路由守卫(在配置路由的时候设置)

 ```
 {
     path: '/test',
     component: testIndex,
     beforeEnter: (to, from, next) => {
         console.log('beforeEnter路由独享的守卫被调用')
         next()
     },
 }
 ```

组件内部守卫

 ```javascript
 mounted () { // 这不是组件守卫,留作测试用
     console.log('mounted被调用了')
 },
 beforeRouteEnter (to, from, next) {
     console.log('beforeRouteEnter被调用:在渲染该组件的对应路由被 confirm 前调用')
     // 在渲染该组件的对应路由被 confirm 前调用
     // 不!能!获取组件实例 `this` 因为当守卫执行前,组件实例还没被创建
     // 可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。
     next(vm => {
         // 通过 `vm` 访问组件实例
         console.log(vm)
     })
 },
 // beforeRouteEnter 是支持给 next 传递回调的唯一守卫。
 // 对于 beforeRouteUpdate 和 beforeRouteLeave 来说,this 已经可用了,所以不支持传递回调,因为没有必要了。
 beforeRouteUpdate (to, from, next) {
     // 在当前路由改变,但是该组件被复用时调用
     // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
     // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
     // 可以访问组件实例 `this`
     console.log('beforeRouteUpdate被调用:在当前路由改变,但是该组件被复用时调用')
     next()
    
 },
 beforeRouteLeave (to, from, next) {
     // 导航离开该组件的对应路由时调用
     // 可以访问组件实例 `this`
     const answer = window.confirm('是否确认离开当前页面')
     if (answer) {
         console.log('beforeRouteLeave被调用:导航离开该组件的对应路由时调用')
         next()
     } else {
         next(false)
     }
 }
 ```