简介
路由就是一套映射规则,当url中的哈希值(#hash)改变时,路由会根据制定好的规则,展示对应的视图组件。
vue中的路由路径分为:相对路径(不带 ‘/’,会拼接父级路由)和 绝对路径(带 ‘/’,是完整的路由)
路由和嵌套路由
引入 vue-router
使用 vue init webpack <project-name>
创建vue项目模板时,默认会引入如下三个组件
- vue
- vuex
- vue-router
确认在 main.js 中已将 vue-router 传递给 vue 的构造函数,vue 的构造函数会自动将router绑定到 vue 的全局,后面使用 this.$router 引用
import router from './router'
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
添加组件
在 components 目录下构造 3 个 vue视图组件
- One.vue
- Two.vue
- Three.vue
第三个组件与 HelloWorld 同级,而前两个组件为 HelloWorld 的子路由
src/components/One.vue
,data 里的数据才是页面可以引用的变量(data上面的是组件名)
<template>
<div>
<h1>{{this.name}}</h1>
<div>{{msg}}</div>
</div>
</template>
<script>
export default {
name: 'One',
data () {
return {
name: '第1个页面',
msg: 'Welcome to First Page'
}
}
}
</script>
src/components/Two.vue
<template>
<div>
<h1>{{this.name}}</h1>
<div>{{msg}}</div>
</div>
</template>
<script>
export default {
name: 'Two',
data () {
return {
name: '第2个页面',
msg: 'Welcome to Second Page'
}
}
}
</script>
src/components/Three.vue
其中 $router.back(-1)
表示返回上一级
<template>
<div>
<h1>{{this.name}}</h1>
<div>{{msg}}</div>
<p>
<button v-on:click="$router.back(-1)">返回上一级</button>
</p>
</div>
</template>
<script>
export default {
name: 'Three',
data () {
return {
name: '第3个页面',
msg: 'Welcome to Third Page, This is a single Page'
}
}
}
</script>
配置路由规则
src/router/index.js
- @符号标识基于src目录
- 如果几个路由使用的是同一个组件,使用 redirect 重定向,而非重复配置
- 绝对路径使用 ‘/’ 打头,相对路径直接以路径名起头
- children 表示嵌套的子路由,将会渲染至当前vue组件的 router-view 中
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import One from '@/components/One'
import Two from '@/components/Two'
import Three from '@/components/Three'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
redirect: 'hello'
},
{
path: '/hello',
name: 'HelloWorld',
component: HelloWorld,
redirect: 'hello/one',
children: [
{
path: 'one',
component: One
},
{
path: 'two',
component: Two
}
]
},
{
path: '/three',
name: 'Three',
component: Three
}
]
})
添加路由切换组件
src/components/HelloWorld.vue
,以 ‘/’ 打头表示绝对路径
<template>
(略)
<div>
<ul>
<li><router-link to=one>子页面1</router-link></li>
<li><router-link to=two>子页面2</router-link></li>
<li><router-link to=/three>独立页面3</router-link></li>
</ul>
<router-view />
</div>
(略)
</template>
实验截图
动态路由
修改 src/components/Three.vue
设置文章列表
<template>
<div>
<h1>Hello World</h1>
<h2>{{this.name}}</h2>
<div>{{msg}}</div>
<p>
<button v-on:click="$router.back(-1)">返回上一级</button>
</p>
<p v-if="err != null">获取数据失败:{{err}}</p>
<p v-else class="articles">
<ul>
<li v-for='article in articles' v-bind:key='article.id'>
<router-link v-bind:to="'/article/' + article.id">{{article.title}}</router-link>
</li>
</ul>
</p>
</div>
</template>
<script>
export default {
name: 'Three',
data () {
return {
name: '第3个页面',
msg: 'Welcome to Third Page, This is a single Page',
articles: [],
err: null
}
},
mounted () {
this.getArticle()
},
methods: {
getArticle () {
this.$fetch.get('api/article').then(res => {
console.log('fetch article', res)
this.articles = res.data
}).catch(_err => {
console.log('axios err', _err)
this.err = _err
})
}
}
}
</script>
<style scoped>
ul {
list-style-type: none;
padding: 0;
text-align: justify;
}
li {
display: block;
margin: 10px;
}
.articles {
display: inline-block;
}
</style>
新建 src/components/Article.vue
用来显示单条文章
<template>
<div>
<h1>Article {{ $route.params.id }}</h1>
<p>{{content}}</p>
</div>
</template>
<script>
export default {
name: 'Article',
data () {
return {
content: ''
}
},
mounted () {
this.getArticle()
},
methods: {
getArticle () {
this.$fetch.get('api/article/' + this.$route.params.id).then(res => {
console.log('fetch article', res, res.data)
if (res.code === 0) {
this.content = res.data.title
} else {
this.content = res.msg
}
}).catch(_err => {
console.log('axios err', _err)
})
}
}
}
</script>
最后对路由进行修改,配置 article 的动态路由
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import One from '@/components/One'
import Two from '@/components/Two'
import Three from '@/components/Three'
import Article from '@/components/Article'
Vue.use(Router)
// function getAbsolutePath () {
// let path = location.pathname
// console.log(path)
// // 输出为/xxx/dist/index.html
// console.log(path.substring(0, path.lastIndexOf('/') - 5))
// return path.substring(0, path.lastIndexOf('/') - 5)
// }
export default new Router({
mode: history,
// base: getAbsolutePath(),
routes: [
{
path: '/',
redirect: 'hello'
},
{
path: '/hello',
name: 'HelloWorld',
component: HelloWorld,
redirect: 'hello/one',
children: [
{
path: 'one',
component: One
},
{
path: 'two',
component: Two
}
]
},
{
path: '/three',
name: 'Three',
component: Three
},
{
path: '/article/:id',
name: 'Article',
component: Article
}
]
})