Vue系列——12-vue-route路由

160 阅读3分钟

​​​​​​​本文已参与「新人创作礼」活动,一起开启掘金创作之路。

目录

vue-router的动态路由

解决ElementUI导航栏中的vue-router在3.0版本以上重复点菜单报错问题 

vue-router的参数传递 

传递参数主要有两种类型:params和query


vue-router是什么

这里的路由并不是指我们平时所说的硬件路由器,这里的路由就是SPA(单页应用)的路径管理器。再通俗的说,vue-router就是WebApp的链接路径管理系统。
vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。传统的页面应用,是用一些超链接来实现页面切换和跳转的。在vue-router单页面应用中,则是路径之间的切换,也就是组件的切换。路由模块的本质 就是建立起url和页面之间的映射关系

至于我们为啥不能用a标签,这是因为用Vue做的都是单页应用(当你的项目准备打包时,运行npm run build时,就会生成dist文件夹,这里面只有静态资源和一个index.html页面),所以你写的标签是不起作用的,你必须使用vue-router来进行管理。

安装Vue-Router之前需要安装脚手架

cnpm install vue-router

或者

vue add router

 在src中新建一个名为router的文件夹里面新建index.js文件

在src中新建一个名为views的文件夹里面新建About.vue和Home.vue文件

index.js部分

切记!!!routes不能打错 

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'

Vue.use(VueRouter)

const routes = [{
  // 当我输入/时会重定向到home里
    path: '/',
    redirect: '/about'
  },
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    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({
  routes
})

export default router

About.vue代码:

<template>
    <div>我是关于页面</div>
</template>

<script>
    export default{
        name:'About'
    }
</script>

<style>
</style>

Home.vue代码如下:

<template>
  <div>我是首页</div>
</template>

<script>
export default {
  name: "Home",
};
</script>

<style>
</style>

App.vue中代码如下:

<template>
  <div id="app">
    <div id="nav">
      <!-- <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link> -->
      <button @click="home">Home</button>
      <button @click="about">About</button>
    </div>
    <router-view />
  </div>
</template>
<script>
export default {
  data(){
    return {}
  },
  methods:{
    home(){
    // this.$router.push('/')
    // this.$router.push({ path: '/' })
    // this.$router.push('Home')
    this.$router.push({name:'Home'})
  },
  about(){
    this.$router.push('/about')
  }
  }
}
</script>
<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

#nav {
  padding: 30px;
}

#nav a {
  font-weight: bold;
  color: #2c3e50;
}

#nav a.router-link-exact-active {
  color: #42b983;
}
</style>

main.js文件如下:

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

new Vue({
  router,
  open:true,
  hot:true,
  render: h => h(App)
}).$mount('#app')

使用路由:通过<router-link><router-view>

<router-link>是全局组件,最终被渲染成a标签,但是<router-link>只是标记路由指向类似一个a标签或者按钮一样,但是我们点击a标签要跳转页面或者要显示页面,所以就要用上<router-view>

<router-view> 是用来占位的,就是路由对应的组件展示的地方,该标签会根据当前的路径,动态渲染出不同的组件。

路由切换的时候切换的是<router-view>挂载的组件,其他不会发生改变。

<router-view>默认使用hash模式,可以在index.js中配置修改为history模式。

app.vue修改template

<router-link>的其他属性

  • to属性:用于跳转到指定路径。
  • tag属性:可以指定之后渲染成什么组件使用会被渲染成一个按钮,而不是a标签。
  • relapce属性:在history模式下指定使用replaceState而不是pushState,此时浏览器的返回按钮是不能使用的。
  • active-class属性:当对应的路由匹配成功的时候,会自动给当前元素设置一个router-link-active的class,设置active-class可以修改默认的名称。
  • 在进行高亮显示的导航菜单或者底部tabbar时,会用到该属性
  • 但是通常不会修改类的属性,会直接使用默认的router-link-active
  • 此时被选中的就会有active的class。
  • 如果每个都要加上active-class='active',那就在路由里面统一更改。 
    <!-- 路由出口 -->
    <!-- 路由匹配到的组件将渲染在这里 -->
    <router-link to="/">home</router-link>  |
    <router-link to="/about">about</router-link>
    <router-view></router-view>        <!-- 显示页面元素 -->

当然,router-view标签可以简写为如下代码,注意:/在后面

<router-view/>

启动浏览器

npm run  serve

效果如下: 

 

修改hash模式为history模式,修改index.js的router对象 

const router = new VueRouter({
  //配置路由和组件之间的应用关系
  routes,
  mode: 'history'//修改模式为history
})

此时发现浏览器地址栏的URL是没有#的。

切换选项卡功能: 

  linkExactActiveClass:'active' 

 给active的class加上字体变红的css。

 

 这里也可以不用router-link标签也能实现页面跳转

Vue Router官网中提到,当你点击 时,这个方法会在内部调用,所以说,点击 等同于调用 router.push(...)。

也可以使用vue ui来直接进行安装

如果使用vue ui安装则无需新建router文件夹以及views文件夹等内容

安装完毕后对代码格式进行配置

 配置完毕后会出现一个js文件

 在文件中修改

module.exports = {
  lintOnSave: false,
  devServer: {
    // 项目构建后路径
    // contentBase: resolve(__dirname, 'build'),
    // 启动gzip压缩
    compress: true,        //是否开启压缩
    // 端口号
    port: 3000,
    // 自动打开浏览器
    open: true,
    hot:true
  },
  
}

即可自动打开浏览器并对其进行实时渲染

vue-router的动态路由

一个页面的path路径可能是不确定的,例如可能有/user/aaaa或者/user/bbbb,除了/user之外,后面还跟上了用户ID/user/123等。这种path和component的匹配关系,叫动态路由。

新建一个组件User

<template>
  <div>
    <h1>User:{{UserId}}</h1>
  </div>
</template>

<script>
export default {
  name: 'User',
  computed:{
      UserId(){
          return this.$route.params.UserId
      }
  }
}
</script>

在App.vue中的template标签里添加以下代码

      <router-link :to="/User/ + UserId">User</router-link> 

script部分: 

export default {
  data() {
    return {
      UserId: '1024',
    };
  },
}

 嵌套路由:

 

嵌套路由就是在一个页面里切换两个两个小页面 

可以把这两个组件写到components文件夹中

 新建两个文件分别为HomeMessage以及HomeNew.vue

HomeMessage.vue内容如下:

<template>
    <div>
        <ul>
            <li v-for="(item,index) in arr" :key="index">{{item}}</li>
        </ul>
    </div>
</template>
<script>
export default {
    name:'HomeMessage',
    data() {
        return {
            arr: ['a,b,c,d,e,f,g,h,i,j'],
        };
    },
}
</script>

HomeNews.vue代码如下:

<template>
    <div>
        <ul>
            <li v-for="(item,index) in arr" :key="index">{{item}}</li>
        </ul>
    </div>
</template>
<script>
export default {
    name:'HomeNews',
    data() {
        return {
            arr: ['1,2,3,4,5,6,7,8,9,10'],
        };
    },
}
</script>

在router中的index.js 的home中添加以下代码

children: [{
        path: '/',
        redirect: '/home/homenews'
      },
      {
        path: '/home/homenews',
        name: 'HomeNews',
        component: () => import('@/components/HomeNews')
      },
      {
        path: '/home/homemessage',
        name: 'HomeMessage',
        component: () => import('@/components/HomeMessage')
      },
    ]

 最后在home.vue中引入这两个组件

<template>
  <div class="home">
    <h1>Home</h1>
    <router-link to="/home/homenews">HomeNews</router-link>|
      <router-link to="/home/homemessage">HomeMessage</router-link>
      <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'Home',
}
</script>

解决ElementUI导航栏中的vue-router在3.0版本以上重复点菜单报错问题 

// 解决ElementUI导航栏中的vue-router在3.0版本以上重复点菜单报错问题
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
  return originalPush.call(this, location).catch(err => err)
}

vue-router的参数传递 

 新建Profile.vue页面

<template>
    <div>
        <h2>档案页面</h2>
        <p>名字为:{{profileInfo.name}}</p>
        <p>性别为:{{profileInfo.sex}}</p>
        <p>身高为:{{profileInfo.height}}</p>
    </div>
</template>
<script>
export default {
    name:"Profile",
    computed:{
        profileInfo(){
        return this.$route.query.profileInfo
    }
    }
}
</script>

index.js部分

  {
    path: '/profile',
    name: 'Profile',
    meta:{title:'档案'},
    component: () => import('@/views/Profile')
  }

 App.vue部分

组件部分: 

<router-link :to="{ path: '/profile', query: { profileInfo } }">档案</router-link>

script部分: 

export default {
  data() {
    return {
      UserId: "1024",
      profileInfo: {
        name: "NC",
        age: 24,
        height: 188,
      },
    };
  },
};

传递参数主要有两种类型:params和query

params的类型也就是动态路由形式

  • 配置路由的格式:/user/:userId
  • 传递的方式:在path后面跟上对应的userId
  • 传递形成的路径:/user/123/user/xxx
  • 通过$route.params.userId获取指定userId

query的类型

  • 配置路由的格式:/profile,也就是普通的配置
  • 传递的方式:对象中使用query的key作为传递的方式
  • 传递形成的路径:/profile?name=NC&age=24&height=188(这个传递的是三个键值对),/profile?profileInfo=%5Bobject%20Object%5D这个query传递的是一个对象的键值对,key为profileInfo,value是一个对象)

name跟的是params

path跟的是query

 完整效果:

 About.vue代码:

<template>
  <div class="about">
    <h1>This is an about page</h1>
  </div>
</template>
<script>
export default {
  name:'About'
}
</script>

Home.vue代码:

<template>
  <div class="home">
    <h1>Home</h1>
    <router-link to="/home/homenews" tag="button">HomeNews</router-link> |
      <router-link to="/home/homemessage" tag="button">HomeMessage</router-link>
      <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'Home',
}
</script>
<style scoped>
.active{
  background-color: rgb(226, 99, 99);
  color: white;
}
</style>

Profile.vue代码:

<template>
  <div>
    <h1>档案页面</h1>
    <p>名字为:{{ profileInfo.name }}</p>
    <p>性别为:{{ profileInfo.sex }}</p>
    <p>身高为:{{ profileInfo.height }}</p>
  </div>
</template>
<script>
export default {
  name: "Profile",
  mounted() {
    console.log(this.$route);
  },
  computed: {
    profileInfo() {
      return this.$route.query.profileInfo;
    },
  },
};
</script>
<style  scoped>
p {
  margin: 10px;
}
</style>

User.vue代码:

<template>
  <div>
    <h1>User:{{ UserId }}</h1>
  </div>
</template>

<script>
export default {
  name: "User",
  computed: {
    UserId() {
      return this.$route.params.UserId;
    },
  },
};
</script>

App.vue代码:

<template>
  <div id="app">
    <div id="nav">
      <!-- <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link> |
      <router-link :to="/User/ + UserId">User</router-link> |
      <router-link :to="{ path: '/profile', query: { profileInfo } }">档案</router-link> -->
      <button @click="goHome">Home</button> |
      <button @click="goAbout">About</button> |
      <button @click="goUser">User</button> |
      <button @click="profileClick">档案</button>
    </div>
    <router-view />
  </div>
</template>
<script>
export default {
  data() {
    return {
      UserId: "1024",
      profileInfo: {
        name: "NC",
        sex: "男",
        height: 188,
      },
    };
  },
  methods: {
    goHome() {
      this.$router.push("/");
    },
    goAbout() {
      this.$router.push("/about");
    },
    goUser() {
      this.$router.push({
        name: "User",
        params: {
          UserId: this.UserId,
        },
      });
    },
    profileClick() {
      this.$router.push({
        path: "/profile",
        query: {
          profileInfo: this.profileInfo,
        },
      });
    },
  },
};
</script>
<style>
* {
  margin: 0;
  padding: 0;
}
ul {
  list-style-type: none;
}
a {
  text-decoration: none;
  color: #2c3e50;
}
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}
#nav {
  padding: 30px;
}
#nav a {
  font-weight: bold;
  color: #2c3e50;
}
#nav a.router-link-exact-active {
  color: #42b983;
}
button {
  width: 120px;
}
.active {
  background-color: rgb(226, 99, 99) !important;
  color: white !important;
}
</style>

components文件夹下的HomeNews.vue代码:

<template>
  <div>
    <br />
    <ul>
      <li v-for="(item, index) in arr" :key="index">{{ item }}</li>
    </ul>
  </div>
</template>
<script>
export default {
  name: "HomeNews",
  data() {
    return {
      arr: ["1,2,3,4,5,6,7,8,9,10"],
    };
  },
};
</script>

HomeMessage.vue代码:

<template>
  <div>
    <br />
    <ul>
      <li v-for="(item, index) in arr" :key="index">{{ item }}</li>
    </ul>
  </div>
</template>
<script>
export default {
  name: "HomeMessage",
  data() {
    return {
      arr: ["a,b,c,d,e,f,g,h,i,j"],
    };
  },
};
</script>

index.js代码:

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,
    children: [{
        path: '/',
        redirect: '/home/homenews'
      },
      {
        path: '/home/homenews',
        name: 'HomeNews',
        component: () => import('@/components/HomeNews')
      },
      {
        path: '/home/homemessage',
        name: 'HomeMessage',
        component: () => import('@/components/HomeMessage')
      },
    ]
  },
  {
    path: '/about',
    name: 'About',
    component: () => import( /* webpackChunkName: "about" */ '@/views/About.vue')
  },
  {
    path: '/user/:UserId',
    name: 'User',
    component: () => import('@/views/User')
  },
  {
    path: '/profile',
    name: 'Profile',
    meta: {
      title: '档案'
    },
    component: () => import('@/views/Profile')
  }
]
// src/router/index.js
const router = new VueRouter({
  routes,
  mode: 'history',
  linkExactActiveClass: 'active'
})
const VueRouterPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(to) {
  return VueRouterPush.call(this, to).catch(err => err)
}

export default router

结构如下:

\