Vue-router
目录
含义
SPA应用(single page application):单页面应用
单页面应用就是用户通过某些操作更改地址栏url之后,动态的进行不同模板内容的无刷新切换,用户体验好。
Vue中会使用官方提供的vue-router插件来使用单页面,原理就是通过检测地址栏变化后将对应的路由组件进行切换(卸载和安装)
与MPA的对比
MPA | SPA | |
---|---|---|
应用构成 | 由多个完整页面构成 | 一个外壳页面和多个页面片段构成 |
跳转方式 | 从一个页面到另一个页面 | 一个页面片段删除或隐藏,加载另一个页面片段并显示 |
跳转后公共资源是否重新加载 | 是 | 否 |
用户体验 | 页面间切换加载慢,不流畅,用户体验差 | 页面片段间切换快,用户体验好,包括移动设备 |
能否实现转场动画 | 否 | 容易实现(手机APP动效) |
页面间传递数据 | 依赖URL 、cookie 或者localstorage ,实现麻烦 | 页面传递数据容易(Vuex 或Vue 中的父子组件通讯props 对象) |
搜索引擎优化(SEO) | 可以直接做 | 需要单独方案(SSR) |
特别适用的范围 | 需要对搜索引擎友好的网站 | 对体验要求高,特别是移动应用 |
简单路由的实现
这里我们需要 vue-router 模块,我们之前搭建项目的时候已经引入了
如果没有引入,就需要用 npm 或 yarn 下载
npm install vue-router -S or yarn add vue-router -S
引入 vue-router,通过Vue.use
来注册插件
router/index.js文件
import Vue from 'vue'
import VueRouter from 'vue-router'
//以下代码如果注释掉,this上面都不存在$router与$route的api了
Vue.use(VueRouter)
创建路由表并配置在路由器中
router/index.js文件
import router1 from "@/views/router1";
const routes = [
{
path: "/router1", //通过这个路径访问
component: router1
}
];
const router = new VueRouter({
routes
});
export default router;
在根实例里注入router,目的是为了让所有的组件里都能通过this. r o u t e r 、 t h i s . router、this. router、this.route来使用路由的相关功能api
src/main.js文件
import router from "./router"
new Vue({
el: '#app',
router, //注册一下 让组件可以通过this.$router or this.$route 使用路由相关的api属性或方法
template: '<App/>',
components: { App }
})
利用router-view来指定路由切换的位置
src/app.vue文件
<router-view></router-view>
使用router-link来创建切换的工具,会渲染成a标签,添加to属性来设置要更改的path信息,且会根据当前路由的变化为a标签添加对应的router-link-active/router-link-exact-active(完全匹配成功)类名
<router-link
to="/router1"
tag="li"
active-class="active">路由1</router-link>
<router-link to="/router2" tag="li" active-class="active">路由2</router-link>
<style lang="scss">
.active {
color: orange;
}
</style>
路由懒加载
懒加载也叫延迟加载,即在需要的时候进行加载,随用随载
{
path: "/router1",
name: "a",
component: resolve => require(["@/views/router1"], resolve)
// component: () => import("@/views/router1") //es6写法
}
多级路由
在创建路由表的时候,可以为每一个路由对象创建children属性,值为数组,在这个里面又可以配置一些路由对象来使用多级路由
{
path: "/router1",
name: "a",
component: resolve => require(["@/views/router1"], resolve),
// component: () => import("@/views/router1")
children: [
{
path: "/router1/child",
component: () => import("@/views/routerChild/child")
}
]
}
二级路由组件的切换位置依然由router-view来指定(指定在父级路由组件的模板中)
默认路由和重定向
当我们进入应用,默认像显示某一个路由组件,或者当我们进入某一级路由组件的时候想默认显示其某一个子路由组件,我们可以配置默认路由
{
path:"/",
redirect:'/films' //重定向 / ==> /films ===> /fimls/nowplaying
},
{
path:"*",
component:Error //前面的路由都没有匹配上的话,就需要显示Error页面了
}
多级路由内部
{
path:"",
redirect:"/films/nowplaying" //进行一级路由内部的重定向操作
}
命名路由
我们可以给路由对象配置name属性,这样的话,我们在跳转的时候直接写name:main就会快速的找到此name属性对应的路由,不需要写大量的urlpath路径了
<router-link
:to="{name:'a'}"
tag="li"
active-class="active">路由1</router-link>
动态路由匹配
有的时候我们需要在路由跳转的时候跟上参数,路由传参的参数主要有两种:路由参数、queryString参数
{
path: "/router2/:id",
component: resolve => require(["@/views/router2"], resolve)
}
可以在页面直接通过 $route.params.id
调用,
在vue对象里面通过 this.$route.params.id
调用
查询字符串携带参数
queryString参数不需要在路由表设置接收,直接设置?后面的内容,在路由组件中通过this.$route.query接收
可以在页面直接通过 $route.query
调用,
在vue对象里面通过 this.$route.query
调用
prop将路由与组件解耦
在组件中接收路由参数需要this.$route.params.id,代码冗余,现在可以在路由表里配置props:true
{
path: "/router2/:id",
name: "b",
props: true,
component: resolve => require(["@/views/router2"], resolve)
}
在路由自己中可以通过props接收id参数去使用了
props:['id']
声明式导航
组件支持用户在具有路由功能的应用中(点击)导航。 通过 to 属性指定目标地址,默认渲染成带有超链接的 标签,可以通过配置 tag 属性生成别的标签.。
<router-link :to="{name:'a'}" tag="li" active-class="active">路由1</router-link>
:to='{name:"detail",params:{id:_new.id},query:{content:_new.content}}'
name是要跳转的路由的名字,也可以写path来指定路径,但是用path的时候就不能使用params传参,params是传路由参数,query传queryString参数
replace属性可以控制router-link的跳转不被记录,active-class属性可以控制路径切换的时候对应的router-link渲染的dom添加的类名
编程式导航
有的时候需要在跳转前进行一些动作,router-link直接跳转,需要在方法里使用$router的方法
this.$router.push()
路由模式
路由有两种模式:hash、history,默认会使用hash模式,但是如果url里不想出现丑陋hash值,在new VueRouter的时候配置mode值为history来改变路由模式
const router = new VueRouter({
mode: "history", //将路由模式改为 history
routes
});
路由原理
hash路由 ====> window.onhashchange监听路径的切换
history路由 ===> window.onpopstate监听路径的切换
history模式,会出现404 的情况,需要后台配置。
所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。
后端配置
nginx
location / {
try_files $uri $uri/ /index.html;
}
原生nodejs
const http = require('http')
const fs = require('fs')
const httpPort = 80
http.createServer((req, res) => {
fs.readFile('index.htm', 'utf-8', (err, content) => {
if (err) {
console.log('We cannot open "index.htm" file.')
}
res.writeHead(200, {
'Content-Type': 'text/html; charset=utf-8'
})
res.end(content)
})
}).listen(httpPort, () => {
console.log('Server listening on: http://localhost:%s', httpPort)
})
如果想知道其他的服务器配置,可以访问vue官网
路由守卫(路由拦截)
在某些情况下,当路由跳转前或跳转后、进入、离开某一个路由前、后,需要做某些操作,就可以使用路由钩子来监听路由的变化
全局路由钩子
//进入到某个路由组件之前
router.beforeEach((to, from, next) => {
//会在任意路由跳转前执行,next一定要记着执行,不然路由不能跳转了
console.log('beforeEach')
console.log(to,from)
next()
})
//进入到某个路由组件之后
router.afterEach((to, from) => {
//会在任意路由跳转后执行
console.log('afterEach')
})
单个路由钩子
只有beforeEnter,在进入前执行,to参数就是当前路由
routes: [
{
path: '/foo',
component: Foo,
//当进入到foo路由之前,就会触发
beforeEnter: (to, from, next) => {
// ...
next() //必须要执行next之后,对应的Foo组件才可以正常显示出来
}
}
]
路由组件钩子
//进入到某个组件之前的拦截,获取不到组件内部的this
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
//离开某个组件之前的拦截,获取到组件内部的this
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
以上就是关于 vue-router 的个人总结,如有不对,欢迎指出~