Vue路由
下载引用
npm install vue-router --save-dev
如果是在模块化工程使用,需要用Vue.use()安装路由功能,然后再所有组件中就可以通过this
访问。
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter);
如果使用全局script标签,则直接引用即可。
<script src="/path/to/vue.js"></script>
<script src="/path/to/vue-router.js"></script>
基本使用
模板:
路由分为两个部分,router-view用来呈现对应路由显示的效果,router-link通过to属性对应每个路由去切换。
<template>
<router-view></router-view>
<div>
<router-link to="/home">home</router-link>
<router-link to="/mine">mine</router-link>
</div>
</template>
脚本代码:
- 引入vue和vue-router,还有所需的组件。
- Vue.use()使用路由
- 创建一个Router实例,包含一个routes数组对应每一个路由。
- 把Router实例挂载到Vue实例上。
import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/home'
import Mine from '@/components/mine'
Vue.use(Router)
//创建一个router管理器实例。
export default new Router({
routes: [
{
path: '/',
redirect: '/home',
component: Home
}
{
path: '/home',
name: 'home',
component: Home
},
{
path: '/mine',
name: 'mine',
component: Mine
}
],
mode: "history"
})
这里用到了重定向,如果访问的是/路径,就重定向到home页。类似的还有别名属性alias。这个应该不难理解,重定向就是你访问a给你定向到b页面;别名则是你给a起了个名字叫b,不管访问的地址是a还是b都会打开a页面。
routes: [
{ path: '/a', component: A, alias: '/b' }
]
挂载到vue实例上
要把router实例挂载到vue实例上,让整个应用都有路由功能。
new Vue({
el: '#app',
router,
})
或者,如果没有el属性,可以手动去挂在到vue实例,
new Vue({
router
}).$mount("#app")
这样我们可以在任何组件都可以通过this.route访问当前路由。
路由的两种模式
hash
Router实例中的mode属性有两种模式(hash/history),默认是hash,是根据onhashchange事件,可以在window上监听这个事件,因为hash发生变化的url都会被浏览器记录下来。
onhashchange事件对象有两个属性,一个是当前页面旧的url,一个是当前页面新的url。
window.onhashchange = function(event){
console.log(event.oldURL, event.newURL);
}
history
但是hash模式下,路由后面就会默认加上一个#号。改成history就没有了#。前面的hashchange,你只能改变#后面的url片段,而history api则给了前端完全的自由。
history可以分为切换和修改,切换的方法如下:
history.go(-2);//后退两次
history.go(2);//前进两次
history.back(); //后退
hsitory.forward(); //前进
修改历史状态包括了pushState,replaceState两个方法,这两个方法接收三个参数:stateObj,title,url
history.pushState({color:'red'}, 'red', 'red'})
window.onpopstate = function(event){
console.log(event.state)
if(event.state && event.state.color === 'red'){
document.body.style.color = 'red';
}
}
history.back();
history.forward();
通过pushstate把页面的状态保存在state对象中,当页面的url再变回这个url时,可以通过event.state取到这个state对象,从而可以对页面状态进行还原,这里的页面状态就是页面字体颜色,其实滚动条的位置,阅读进度,组件的开关的这些页面状态都可以存储到state的里面。
history可能存在的问题就是,如果服务端没有对应的资源响应的话,用F5刷新就可能会出现404。
动态路由
很多时候我们需要根据某个参数对同一个页面进行不同的渲染。比如从列表到详情也就是这种需求,所以我们需要动态路由来匹配。
export default new Router({
routes: [
{
path: '/home/:id',
name: 'home',
component: Home
}
]
})
const Home = {
template: "<p>home {{ $route.params.id }}</p>"
}
以上代码id参数使用冒号标记,当匹配到一个路由时,参数就会被设置到this.route.params就是{id: 12}
以上这种方式获取参数虽然可以,但是会使其对应的路由形成高度耦合。我们可以通过props来传参。上面代码可以改成以下:
const Home = {
props: ['id'],
template: "<p>home {{ id }}</p>"
}
export default new Router({
routes: [
{
path: '/home/:id',
component: Home,
props: true
}
]
})
props为true,route.params将被设置为组件属性,从props离获取到,也可以是一个对象或者有返回值的函数。
路由传参
1. 编程式路由传参
配置路由:
{
path: '/coustomer/tags',
name: 'tags',
component: Tags
}
跳转时添加params参数,
this.$router.push({ name: "tags", params: { from: "detail" } });
跳转成功后,在tags这个页面可以访问到:
console.log(this.$route.params); // {from: 'detail'}
2. 使用query传递
和使用params一样,替换成query即可,这样的传递参数会在url后面显示。在页面中也可以直接获得。
this.$route.query.from
路由嵌套
这里的<router-view>是顶层的出口,同样一个被渲染的组件也可以包含自己的路由。
<div id="app">
<router-view></router-view>
<div>
<router-link to="/user/foo">/user/foo</router-link>
<router-link to="/user/foo/profile">/user/foo/profile</router-link>
<router-link to="/user/foo/posts">/user/foo/posts</router-link>
</div>
</div>
我们在User组建的模板添加一个<router-view>
const User = {
template: `
<div class="user">
<h2>User {{ $route.params.id }}</h2>
<router-view></router-view>
</div>
`
}
const UserHome = { template: '<div>Home</div>' }
const UserProfile = { template: '<div>Profile</div>' }
const UserPosts = { template: '<div>Posts</div>' }
在VueRoyuter实例中使用children配置,为了避免访问/user/foo时页面没有渲染,我们提供一个空的路由匹配UserHome 模板。
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User,
children: [
// UserHome will be rendered inside User's <router-view>
// when /user/:id is matched
{ path: '', component: UserHome },
// UserProfile will be rendered inside User's <router-view>
// when /user/:id/profile is matched
{ path: 'profile', component: UserProfile },
// UserPosts will be rendered inside User's <router-view>
// when /user/:id/posts is matched
{ path: 'posts', component: UserPosts }
]
}
]
})