本文已参与「新人创作礼」活动,一起开启掘金创作之路。
目录
解决ElementUI导航栏中的vue-router在3.0版本以上重复点菜单报错问题
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
结构如下:
\