学习Vue-Router
理解路由
什么是前端路由
路由概念来源于服务端,在服务端中路由就是URL和相应处理函数的映射。
在WEB的SPA中,路由是URL和UI的映射,这种映射是单向即URL引起UI的变化(无需刷新页面)
如何实现前端路由?
hash实现
hash 是 URL 中 hash (#) 及后面的那部分,常用作锚点在页面内进行导航,改变 URL 中的 hash 部分不会引起页面刷新
通过 hashchange 事件监听 URL 的变化,改变 URL 的方式只有这几种:通过浏览器前进后退改变 URL、通过标签改变 URL、通过window.location改变URL,这几种情况改变 URL 都会触发 hashchange 事件
history实现
history 提供了 pushState 和 replaceState 两个方法,这两个方法改变 URL 的 path 部分不会引起页面刷新
history 提供类似 hashchange 事件的 popstate 事件,但 popstate 事件有些不同:通过浏览器前进后退改变 URL 时会触发 popstate 事件,通过pushState/replaceState或标签改变 URL 不会触发 popstate 事件。好在我们可以拦截 pushState/replaceState的调用和标签的点击事件来检测 URL 变化,所以监听 URL 变化可以实现,只是没有 hashchange 那么方便。
基础
1.安装
NPM
npm install vue-router
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter) //Vue.use注册后可全局使用,在调用启动应用之前,自动阻止多次注册相同插件
VUE CLI
以项目插件的形式添加
vue add router
构建开发版
直接从gitlab上clone,然后build
git clone https://github.com/vuejs/vue-router.git node_modules/vue-router
cd node_modules/vue-router
npm install
npm run build
2.起步
将组件 (components) 映射到路由 (routes),然后告诉 Vue Router 在哪里渲染它们
HTML
使用router-link来导航,to指定链接,默认被渲染成一个a标签
< router-link :to="/foo" >Go to Foo< /router-link >
路由匹配到的组件渲染到router-view
< router-view >< /router-view >
Javascript
第一步:定义组件
var Foo={template:' < div>Foo< /div> '}
第二步:在定义路由,其中path为自定义的路径名称,component为对应路径的组件
var routes=[
{ path:'/foo' ,component:Foo},
]
第三步:创建router实例
const router=new Router({
routes //本来为routes:routes,ES6可简写为routes
})
第四步:创建和挂载在vue实例上
const app=new Vue({
router
}).$mount('#app')
在任意组件中可通过this.$ router访问路由器或this.$ route访问当前路由
因为vm的显式原型和vc的隐式原型指向同一个对象,vm的显示原型和实例的隐式原型指向同一个对象,所以组件实例也可以访问router就是包含整个路由的路由器;
可是route是哪儿?
this.$ router和this.$ route的区别:
①this. $ router:
相当于一个全局的路由对象,包含很多属性和对象(例如history对象)
任何页面都可以调用其push()、history()、go()方法
② this.$ route:
相当于一个局部的路由对象,只表示当前路由对象,每个路由都有一个路由对象,可以获取其name、path、params和query等属性
例:
访问当路由某参数this.$ route.params.username
返回上一页this.$ router.go(-1)
动态路由
动态路由匹配
动态路由参数以冒号开头:
routes: [
{ path: '/user/:id', component: User }
]
当匹配到一个路由时,参数值会被设置到 this.$ route.params,可以在每个组件内使用。
例:this.$ route.params.id //当前组件路由参数的id字段
可设置多段路由参数
例:‘/username/:user/post/:userid’
匹配路由 ‘username/jesscia/post/1128/’
则,获得的参数为{user:'jessica ',userid:‘1128’}
其他参数,this.$ route.query(查询参数)、this.$ route.hash
响应路由参数的变化
从/user/foo到/user/bar,原来的组件会被复用,因为都在同个组件只是后面的参数不同而生命周期的钩子也不会再被调用
如果想对路由变化做出反应,可以使用watch监测
例:
watch:{
$route(to,from){
//对路由变化做出的响应
}
}
匹配所有路由或404 NOT FOUND路由
常规参数只会匹配被 / 分隔的 URL 片段中的字符,想匹配所有路由可以用通配符*
{
// 会匹配所有路径
path: '*'
}
{
// 会匹配以 `/user-` 开头的任意路径
path: '/user-*'
}
使用通配符的路由通常放在后面,path:’*'通常用于客户端404错误
使用通配符,$ route.params会加一个pathMatch参数
//path:' /user-* '
$ router.push('/user-admin')
$ route.params.pathMatch //admin
//path:' * '
this.$ router.push('/404 NotFound')
this.$ route.params.pathMatch //404 NotFound
高级匹配模式
使用path-to-regexp作为路由匹配引擎,例如可以匹配0个至多个路由,或者指定其匹配的正则表达式
匹配优先级
优先级与路由顺序有关,路由定义越早,优先级越高
嵌套路由
import Vue from "Vue"
import VueRouter from "vue-router"
Vue.use(VueRouter)
//App.vue
<div id="app">
<router-view></router-view> //此为顶层路由出口,渲染最高级路由匹配到的组件
</div>
const var router=new VueRouter({
routes:[
{
path:'/user',
component: User
children:[
{
// 当 /user/foo 匹配成功,
// Foo组件 会被渲染在 User 的 <router-view> 中
path:'foo',
component:Foo
},
]
},
]
})
const add=new Vue({
router
} ).$mount(#app) //使用vue实例上的$mount直接挂载
//最上层为user,但是可在user中任然使用router-view去渲染children中的路由
注:以/开头的路劲会被当做根路径,所以再嵌套路由中只需写其嵌套的组件
当嵌套路由中没有匹配的路由,可以提供一个空的子路由
例:
children:[
{
path:' ',
component:UserHome
}
//当只有' /user '时会匹配到此组件,则会渲染此组件,而在其他匹配子路由就渲染相应的组件
]
编程式导航
router.push()
除了使用< router-link/>创建a标签来定义导航组件,还可以使用$ router.push()
注意:在 Vue 实例内部,你可以通过 $ router 访问路由实例(路由器)。因此你可以调用 $router.push。
导航到不同的url,可以使用push(),这个方法可以想history栈新填一个记录,当用户点击返回时则会回到之前的url //$router.go(-1)
点击< router-link/>时,会在内部调用 r o u t e r . p u s h 声 明 式 : < r o u t e r − l i n k : t o = " / f o o " > < / r o u t e r − l i n k > 编 程 式 : router.push 声明式:< router-link :to="/foo"></ router-link> 编程式: router.push声明式:<router−link:to="/foo"></router−link>编程式:router.push("/foo")
该方法的参数:
//字符串
$router.push('home')
//对象
$router.push({path:'home'})
//命名的路由
$router.push({name:'user',params:{userId:'123'}})
//带查询参数 /register?plan=private
$router.push({path:'register',query:{plan:'private'}})
注:如果提供了path和params会被忽略
应如下使用(同样使用于< router-link>的to属性):
const userId='123'
$router.push({name:'user',params:{userId}})//使用name和params组合
或
$router.push({path:`/user/${userId}`})//使用模板字符串
$router.push(path:'/user',params:{userId})// -> /user
params和query的区别:
①params
$router.push({path:“地址”,query:{id:“123”}}); //这是传递参数$route.query.id; 这是接受参数
②query
$router.push({name:“地址”,params:{id:“123”}}); 这是传递参数$route.params.id; 这是接受参数
//
params使用path编写传参地址,query使用name编写传参地址
接收方法就是谁传的谁接收
query在刷新页面时参数不会变,而params刷新页面时参数会消失,采用本地存储解决、
query传的参数会显示在url地址栏,params的参数不会
在2.2.0+版本:
可选的push()和replace()中onComplete、onAbort两个回调函数分别作为第二第三参数,在导航成功或中止进行相应的调用
注:如果当前路由和目的地相同,例如只是参数发生了改变,需使用beforeRouteUpdat()来响应这个变化
router.replace()
$ router.replace(location,onComplete?,onAbort?)
replace不会向history栈对象添加记录,而是替换当前记录
点击< router-link/>时,会在内部调用 r o u t e r . p u s h 声 明 式 : < r o u t e r − l i n k : t o = " / f o o " r e p l a c e > 编 程 式 : router.push 声明式:< router-link :to="/foo" replace> 编程式: router.push