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>
原文地址:https://www.cnblogs.com/zhangruifeng/p/13533779.html