• Vue路由


    Vue Router

    使用Vue路由之前我们需要先安装router组件,由于VueCli4以上的版本可以很方便的使用vue ui添加vue router组件,所以这里就不再做详细的说明了。

    使用Router

    修改router/index.js

    router的使用非常的简单,首先我们需要在index.js中添加路由规则。下面介绍了两种路由的注册方式

    1、引入组件

    2、创建router,修改模式为history

    3、添加Vue.use(VueRouter)

    4、创建routers,指定路由规则

    5、在router中引入routers

    6、将router导出

    使用redirect可以进行重定向,定向到其他路由中。但是一定要注意,重定向到的路由一定要在此之前声明!!

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    import Home from '../views/Home.vue'
    
    Vue.use(VueRouter)
    
      const routes = [
      {
        path: '/',
        name: 'Home',
        component: Home
      },
      {
        path: '',
        redirect: '/'
      },
      {
        path: '/about',
        name: 'About',
        // route level code-splitting
        // this generates a separate chunk (about.[hash].js) for this route
        // which is lazy-loaded when the route is visited.
        component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
      }
    ]
    
    const router = new VueRouter({
      mode: 'history',
      base: process.env.BASE_URL,
      routes
    })
    
    export default router
    
    

    route中支持自定义属性!

    在main.js中引入路由规则

    当导入的是某个文件夹下的index.js时,可以直接使用文件夹代替

    1、导入组件

    2、导入router/index.js

    3、在Vue中注册路由

    import Vue from 'vue'
    import App from './App.vue'
    import router from './router'
    import './plugins/element.js'
    
    Vue.config.productionTip = false
    
    new Vue({
      router,
      render: h => h(App)
    }).$mount('#app')
    
    

    在App.vue中使用路由

    使用router-link标签使用路由

    tag可以指定router-link使用什么组件代替

    replace指定页面是否可以回退

    router-view标签指定路由组件出现的位置

    <template>
      <div id="app">
        <router-link to="/" tag="button" replace>首页</router-link>
        <router-link to="/about" tag="button">关于</router-link>
        <router-view></router-view>
      </div>
    </template>
    
    <script>
    
    export default {
      name: 'app',
      components: {
      }
    }
    </script>
    
    <style>
    #app {
      font-family: 'Avenir', Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    </style>
    
    

    设置当前激活项的前景色

    当选中某个页面时,我们经常要改变其样式,如果单独控制会非常麻烦,可以在App.vue中创建一个样式:

    .active{
      color: red;
    }
    

    在index.js中设置激活link的样式即可

    const router = new VueRouter({
      mode: 'history',
      base: process.env.BASE_URL,
      linkActiveClass: 'active',
      routes
    })
    

    使用事件调用路由

    不能使用原生进行路由,必须由router路由进行

    自定义事件使用路由的方法非常简单,使用this.$router.push("/");即可,但是一定要注意加上<router-view></router-view>

    <template>
      <div id="app">
        <router-link to="/" replace>首页</router-link>
        <router-link to="/about" replace>关于</router-link>
        <router-view></router-view>
        <button @click="homePage">首页</button>
        <button @click="aboutPage">关于</button>
      </div>
    </template>
    
    <script>
    export default {
      name: "app",
      methods: {
        homePage: function () {
          this.$router.push("/");
        },
        aboutPage: function () {
          this.$router.push("/about");
        }
      },
      components: {},
    };
    </script>
    
    <style>
    #app {
      font-family: "Avenir", Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    </style>
    
    

    动态路由

    在某些情况下,一个页面的path路径可能事不确定的,比如我们进入用户界面时,希望如下的路径:

    /user/aaaa或者/user/bbbb,除了前面的user之外,后面还跟上了用户的id。上述的需求就称之为动态路由。

    先配置user的路由

    在user后添加一段/:flag

      {
        path: '/user/:userId',
        name: 'User',
        component: User
      }
    

    在App.vue中是使用

    此时在App.vue中,添加动态属性

      data() {
        return {
          userId: "rayfoo"
        };
      },
    

    此时,即可使用动态路由

    <router-link :to="'/user/'+userId" replace>用户</router-link>
    

    在组件中获取动态路由的属性

    如果跳转到对应页面后,需要获取动态路由中的属性,可以使用$route获取

    (route和)router不同,前者是获取当前活跃的路由,而后者是全局路由对象

    <template>
        <div id="app">
            <h2>我是用户页面</h2>
            <p>我是用户的相关信息</p>
            <p v-text="userId"></p>
        </div>
    </template>
    
    <script>
    export default {
        name: "User",
        computed: {
            userId(){
                //获取当前活跃的路由
                return this.$route.params.userId;
            }
        }
    };
    </script>
    
    <style>
    </style>
    

    打包文件的解析

    vue文件执行打包命令之后,所有js文件会编译为三个js文件

    • app.hash.js 用户的业务代码
    • chunk-vendors.hash.js Vue及第三方插件代码
    • about.hash.js 项目的一些信息

    路由的懒加载

    当项目达到一定量级,app.hash.js中的代码会越来越大,当用户首次访问页面的时候,加载的事件会过长,所以我们可以将项目分为若干块,使用路由进行懒加载。

    可以使用路由,将每个路由都打包为一个js文件,当使用某个路由时,再去加载对应的资源。

    在上面的index.js中,aubot的引入代码如下。如果英文好的话,可以看出其注释中说明了这是一种懒加载的形式,所以在上面的代码中会有一个about.hash.js文件

      {
        path: '/about',
        name: 'About',
        // route level code-splitting
        // this generates a separate chunk (about.[hash].js) for this route
        // which is lazy-loaded when the route is visited.
        component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
      }
    

    也可以使用下面的形式,进行懒加载(推荐)

    使用懒加载后的数据会被打包为chunk-hash.hash.js

    //lazy-loaded
    const User = () => import('../views/User.vue')
    
      {
        path: '/user/:userId',
        name: 'User',
        component: User
      }
    

    使用懒加载可以大大的提高页面的渲染效率,尽量保证每个路由都以懒加载形式引入。

    路由嵌套

    路由嵌套是一个很常见的功能

    比如在home页面中,我们希望通过/home/news和/home/message,访问一些内容

    一个路径映射一个组件,访问这两个路径也会分别渲染这两个组件

    路由嵌套的使用步骤

    1、创建对应的子组件

    2、在路由映射中配置对应的子路由

    需要注意的是,子路由中,千万不要加/前缀!

    {
        path: '/home',
        name: 'Home',
        component: Home,
        children: [
          {
            path: 'news',
            component: () => import('../views/home/news.vue')
          },
          {
            path: 'message',
            component: () => import('../views/home/message.vue')
          }
        ]
      }
    

    如果需要指定默认加载的子路由,可以新增一个默认的子路由+使用redirect来实现

    {
        path: '/home',
        name: 'Home',
        component: Home,
        children: [
          {
            path: '',
            redirect: 'news'
          },
          {
            path: 'news',
            component: () => import('../views/home/news.vue')
          },
          {
            path: 'message',
            component: () => import('../views/home/message.vue')
          }
        ]
      }
    

    3、在Home组件内部使用标签

    <template>
      <div class="home">
        <h1>我是首页</h1>
        <p>我是内容</p>
        <router-link to="/home/news">新闻</router-link>
        <router-link to="/home/message">消息</router-link>
        <router-view></router-view>
      </div>
    </template>
    
    <script>
    
    export default {
      name: 'Home'
    }
    </script>
    
    

    路由之间的消息传递

    路由传递主要有两种类型,params和query

    param类型

    • 配置路由的格式:/router/:id

    • 传递的方式:在path后面跟上对应的值

    • 传递后形成的路径:/router/123,/router/abc

    前面介绍的动态路由中使用的this.$route.params.val;就是param进行传递参数的方法,详细的内容请看h2:[动态路由]

    query的类型

    • 配置路由的格式:/router,也就是普通的配置
    • 传递的方式:对象中使用query的key作为传递方式
    • 传递后形成的路径:/router?id=123,/router?id=abc

    下面我们介绍另一种更加优雅的写法:query

    传递参数:

    <router-link :to="{path:'/profile',query:{name:'rayfoo',age:18}}" replace>我的</router-link>
    

    取出参数:

    <template>
      <div id="profile">
        <h1>我的</h1>
        <p v-text="$route.query"></p>
        <p v-text="$route.query.name"></p>
      </div>
    </template>
    
    <script>
    export default {};
    </script>
    
    <style>
    </style>
    

    事件中使用query

    案例代码:

    <template>
      <div id="app">
        <router-link to="/" replace>首页</router-link>
        <router-link to="/about" replace>关于</router-link>
        <router-link :to="'/user/'+userId" replace>用户</router-link>
        <router-link :to="{path:'/profile',query:{name:'rayfoo',age:18}}" replace>我的</router-link>
        <router-view></router-view>
        <button @click="homePage">首页</button>
        <button @click="aboutPage">关于</button>
        <button @click="userPage">用户</button> 
        <button @click="profilePage">我的</button>
      </div>
    </template>
    
    <script>
    export default {
      name: "app",
      data() {
        return {
          userId: "rayfoo"
        };
      },
      methods: {
        //此处多次点击会报错,这是因为跳转页面重复了 可以进行判断
        homePage: function () {
          this.$router.push("/");
        },
        aboutPage: function () {
          this.$router.push("/about");
        },
        userPage: function(){
          this.$router.push("/user/" + this.userId);
        },
        profilePage: function(){
          this.$router.push({
            path: '/profile',
            query: {
              name: 'giao',
              age: 25
            }
          });
        }
      },
      components: {}
    };
    </script>
    
    <style>
    #app {
      font-family: "Avenir", Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    </style>
    
    

    解决自定义事件路由跳转多次点击报错的问题

    在main.js的下方添加如下代码即可解决:

    import Router from 'vue-router'
    
    const originalPush = Router.prototype.push
    Router.prototype.push = function push(location) {
      return originalPush.call(this, location).catch(err => err)
    }
    
    

    导航守卫

    所谓导航守卫就是当Vue路由发生前后,对其的监听,我们就可以对相应的操作进行监听和操作。个人感觉其类似于后端的AOP、拦截器等思想。

    前置钩子

    前置守卫是对路由跳转之前的监听,它可以实现权限校验等操作。

    需求:加载不同组件的时候,标题显示与之对应的值

    解决方案1:使用生命周期函数

    可以借助组件生命周期函数中的created()来进行监听,使用document.title设置标题内容。但是不能因为这一个需求改变所有的组件。

    解决方案2:使用全局前置守卫

    利用route中的自定义属性name+前置守卫实现title的设置。

    //前置守卫
    router.beforeEach((to,from,next)=>{
      //从from去to
      document.title = to.matched[0].name
      next()
    })
    

    使用matched是避免多级url中调用的问题。如果没有多级路径可以直接使用to.name

    当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中

    每个守卫方法接收三个参数:

    • to: Route: 即将要进入的目标 路由对象
    • from: Route: 当前导航正要离开的路由
    • next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
      • next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
      • next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
      • next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: truename: 'home' 之类的选项以及任何用在 router-linkto proprouter.push 中的选项。
      • next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

    //后置钩子 必须使用to和from 否则会报错!

    router.afterEach((to, from) => {

    // ...

    console.log(to)

    console.log(from)

    })

    关于守卫(钩子)的介绍可以参考下面的内容

    https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%85%A8%E5%B1%80%E5%89%8D%E7%BD%AE%E5%AE%88%E5%8D%AB

    keep-alive和router-view

    keep-alive是一个vue内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。

    router-view也是一个组件,如果直接包在keep-alive里面,所有路径匹配到的视图组件都会被缓存。

    前面我们已经使用过router-view来渲染页面

    router-viwe的生命周期

    在每个组件中,都各自添加一个生命周期函数created和destoryed,添加打印消息。

    export default {
      name: 'Home',
      created(){
          console.log("home created");
      },
      destroyed(){
        console.log("home destoryed");
      }
    }
    

    使用router-view进行路由显示时发现,当页面被加载时会执行created方法,切换到其他页面的时候。会执行destoryed方法。说明router-viwe渲染的组件是每次都会重新初始化和销毁的。

    在App.vue中使用此标签,可以解决上述重复渲染的问题,但是这也意味着页面不会重新被渲染。需要根据使用的情况而定。

        <keep-alive>
          <router-view></router-view>
        </keep-alive>
    

    keep-alive中存在子路由如何处理?

    路由发生后,如果跳转的页面中存在子路由。如果子路由没有进行keep-alive处理,子组件仍然会重复的进行创建、销毁等操作。并且子组件的状态不会被保存,我们可以通过在子路由中使用keep-alive以及守卫来解决这个问题。

    解决子路由重复渲染

    解决子组件重复渲染问题,我们可以像上面一样,在子路由的router-viwe上加入keep-alive标签

    解决子路由状态保留问题

    首先介绍两个方法

    activated:当组件处于活跃状态时执行

    beforeRouterLeave:导航离开该组件的对应路由时调用

    使用上面两个方法加自定义属性path来记录当前的path

    完整代码:

    <template>
      <div class="home">
        <h1>我是首页</h1>
        <p>我是内容</p>
        <router-link to="/home/news">新闻</router-link>
        <router-link to="/home/message">消息</router-link>
        <keep-alive>
          <router-view/>
        </keep-alive>
      </div>
    </template>
    
    <script>
    
    export default {
      name: 'Home',
      data(){
        return{
          path: '/home/news'
        }
      },
      created(){
          console.log("home created");
      },
      destroyed(){
        console.log("home destoryed");
      },
      activated(){
        this.$router.push(this.path);
      },
      beforeRouteLeave (to, from, next) {
        console.log(this.$route.path);
        this.path = this.$route.path;
        next()
      }
    }
    </script>
    
    

    补充:activated、deactivated,只有keep-alive添加时才会生效!

    keep-alive属性介绍

    前面的案例中,介绍了组件重复渲染的解决方案,但是所有组件都不会被重新的渲染

    存在需求如下:

    ​ 存在五个组件,其中有一个组件需要实时渲染,其余四个不需要。

    keep-alive中的属性

    keep-alive中存在两个非常重要的属性:

    • include-字符串或正则表达式,只有匹配的组件会被缓存

    • exclude-字符串或正则表达式,任何匹配的组件都不会被渲染

    使用这两个属性,我们就可以解决上面的需求

    在App.vue的keep-alive加入如下属性,即可解决此问题

    其中Profile、Home均为组件的name属性,多个之间使用逗号间隔

    注意:不要再此属性内加上“空格”等字符

        <keep-alive exclude="Profile,Home">
          <router-view></router-view>
        </keep-alive>
    
    export default {
      name: "Profile",
      created() {
        console.log("Profile created");
      },
      destroyed() {
        console.log("Profile destoryed");
      }
    };
    </script>
    
  • 相关阅读:
    《淘宝网》之系统质量属性分析
    《架构漫谈》读后感 之“关于软件架构师如何工作”
    《软件需求》读后感06
    《软件需求》读后感05
    Cforeach的详细用法--【转】
    事件(Event)(onclick,onchange,onload,onunload,onfocus,onblur,onselect,onmuse)【转载】
    十七、Mysql的主从(一)--主从原理
    十七、Mysql的主从(二)--主从复制部署
    十六、mysql的备份与恢复(三)--xtrabackup(XBK、Xbackup)
    十六、mysql的备份与恢复(二)--mysqldump
  • 原文地址:https://www.cnblogs.com/zhangruifeng/p/13533779.html
Copyright © 2020-2023  润新知