路由其实就是url和文件的映射,在后端控制路由在接收到客户端发来的http请求时,会根据响应的url来找到相应的映射函数,执行得到返回值给客户端。对于简单的静态资源服务,所有url的映射函数是一个文件读取操作;对于动态资源,映射函数可能是个数据库读取操作,也可能是一些数据的处理等等。然后根据读取的数据路由,在服务端使用相应的模板对页面进行渲染后,在返回渲染完毕的页面。
服务端控制的路由来实现服务端渲染,服务端渲染的优缺点在于:
服务端控制路由本质是url和文件读取操作的映射,而前端路由是进行dom元素的显示和隐藏操作,在访问不同路径时显示不同的组件。当前前端路由主要有两种实现方式:hash模式和history模式。
前端路由的优缺点在于:
vue-router有两种路由模式,分别是hash模式和history模式,在路由配置中默认的是hash模式。
早期的前端路由是基于location.hash来实现的,对此在react-router和vue-router都是默认将hash路由作为路由模式的。hash模式的url默认带有#,location.hash的值就是url的#后面的内容。
在vue-router中,对于http://blog.onechuan.cn/#/login的hash值就是#/login。
特点:
使用: 切换hash路由的方式有两种
对此,可以看到hash路由的实现就是基于hashchange事件进行监听。
原理:
hash模式的主要原理就是onhashchange()事件:
window.onhashchange = function(event){
console.log(event.oldURL, event.newURL);
let hash = location.hash.slice(1);
}
使用onhashchange()的优点:
history模式的url中没有#,看起来也比hash模式更美观,本质是通过传统的路由分发模式,即用户输入一个url时,服务器会接收请求并解析这个URL,然后做出相应的逻辑处理。
当使用history模式时,URL就像这样:https://blog.onechuan.cn/user/id。
特点:
原理:
history模式主要依赖于:history.pushState()和 history.repalceState() 两个api来实现不进行刷新的情况下,操作浏览器的历史记录。
修改历史状态:history.pushState()和 history.repalceState()提供了对历史记录进行修改的功能。只是当他们进行修改时,虽然修改了url,但浏览器不会立即向后端发送请求。如果要做到改变url但又不刷新页面的效果,就需要前端用上这两个API。
切换历史状态:包括forward()、back()、go()三个方法,对应浏览器的前进、后退、跳转操作
pushState和repalceState不会触发popstate 事件,这时我们需要手动触发页面渲染。
缺点:在刷新页面的时候,如果没有相应的路由或资源,就会刷出404来。
对比点 | hash模式 | history模式 |
---|---|---|
原理 | onhashchange() | history.pushState()和 history.repalceState() |
兼容性 | >= ie 8,其它主流浏览器 | >= ie 10,其它主流浏览器 |
实用性 | 不需要对服务端做改动 | 需要服务端配置支持 |
// 监听,当路由发生变化的时候执行
watch: {
$route: {
handler: function(val, oldVal){
console.log(val);
},
// 深度观察监听
deep: true
}
}
window.location.hash 的值可读可写,读取来判断状态是否改变,写入时可以在不重载网页的前提下,添加一条历史访问记录。
const List = () => import('@/components/list.vue')
const router = new VueRouter({
routes: [
{ path: '/list', component: List }
]
});
const router = new Router({
routes: [
{
path: '/list',
component: resolve => require(['@/components/list'], resolve)
}
]
});
这种情况下,多个路由指定相同的chunkName,会合并打包成一个js文件。
// r就是resolve
const List = r => require.ensure([], () => r(require('@/components/list')), 'list');
// 路由也是正常的写法 这种是官方推荐的写的 按模块划分懒加载
const router = new Router({
routes: [
{
path: '/list',
component: List,
name: 'list'
}
]
}));
定义动态路由
//在APP.vue中
<router-link :to="`/user/${userId}`" replace>用户</router-link>
//在router.js
{
path: '/user/:userid',
component: User,
}
路由跳转
// 方法1:
<router-link :to="{ name: 'users', params: { uname: oenchuan }}">按钮</router-link>
// 方法2:
this.$router.push({name:'users',params:{uname:onechuan}})
// 方法3:
this.$router.push(`/user/${onechuan}`);
参数获取通过 $route.params.userid 获取传递的值。
路由定义
//方式1:直接在router-link 标签上以对象的形式
<router-link :to="{path:'/profile',query:{name:'why',age:28,height:188}}">档案</router-link>
// 方式2:写成按钮以点击事件形式
<button @click='profileClick'>我的</button>
profileClick(){
this.$router.push({
path: "/profile",
query: {
name: "kobi",
age: "28",
height: 198
}
});
}
跳转方法
// 方法1:
<router-link :to="{ name: 'users', query: { uname: james }}">按钮</router-link>
// 方法2:
this.$router.push({ name: 'users', query:{ uname:james }})
// 方法3:
<router-link :to="{ path: '/user', query: { uname:james }}">按钮</router-link>
// 方法4:
this.$router.push({ path: '/user', query:{ uname:james }})
// 方法5:
this.$router.push('/user?uname=' + james)
获取参数
通过$route.query 获取传递的值。
对比点 | params | query |
---|---|---|
引入方式 | 用name来引入 | 用path来引入 |
接收参数 | this.$route.params.name | this.$route.query.name |
url地址显示 | params则类似于post,url不显示参数 | query更加类似于ajax中get传参,url显示参数 |
刷新页面 | params刷新会丢失 params里面的数据 | query刷新不会丢失query里面的数据 |
路由导航、keep-alive、和组件生命周期钩子结合起来的,触发顺序,假设是从a组件离开,第一次进入b组件∶
在一些场景,比如:最常见的登录权限验证,当用户满足条件时,才让其进入导航;否则就取消跳转,并跳到登录页面让其登录。
为此有很多种方法可以植入路由的导航过程:
全局路由钩子
vue-router全局有三个路由钩子;
具体使用∶
router.beforeEach((to, from, next) => {
let ifInfo = Vue.prototype.$common.getSession('userData'); // 判断是否登录的存储信息
if (!ifInfo) {
// sessionStorage里没有储存user信息
if (to.path == '/') {
//如果是登录页面路径,就直接next()
next();
} else {
//不然就跳转到登录
Message.warning("请重新登录!");
window.location.href = Vue.prototype.$loginUrl;
}
} else {
return next();
}
});
router.afterEach((to, from) => {
// 跳转之后滚动条回到顶部
window.scrollTo(0,0);
});
单个路由独享钩子
beforeEnter 如果不想全局配置守卫的话,可以为某些路由单独配置守卫,有三个参数∶ to、from、next
export default [
{
path: '/',
name: 'login',
component: login,
beforeEnter: (to, from, next) => {
console.log('即将进入登录页面')
next()
}
}
]
组件内钩子
beforeRouteUpdate、beforeRouteEnter、beforeRouteLeave这三个钩子都有三个参数∶to、from、next
注意点,beforeRouteEnter组件内还访问不到this,因为该守卫执行前组件实例还没有被创建,需要传一个回调给 next来访问,例如:
beforeRouteEnter(to, from, next) {
next(target => {
if (from.path == '/classProcess') {
target.isFromProcess = true
}
})
}
来源: 前端一码平川
在使用vue-cli搭建的环境中,浏览器上URL地址中是存在#的,这是由于vue-router 默认 hash 模式,不难发现#的出现真的很丑陋。官网给出了如何使用history模式mode: history
vue中路由传参主要的3种方式:query方式(push时使用path来匹配)、params模式(push时使用name来匹配)、location预声明参数模式(push使用path来匹配,但是它跟params模式不同)
我们的通用的后台管理系统中,我们会根据权限的粗细不同,会对每个角色每个权限每个资源进行控制。同样的我们也需要实现一个这样的功能。 这篇文章我将主要讲vue端的实现,关于后台接口我就不会涉及,当我接触的时候我们的后台接口是springcloud实现。
前后端分离开发模式,后端会把路由控制丢在前端,这几天再开发单页面小的项目,手动撸了个路由。前端路由实现有两种方法。HTML5 History API包括2个方法:history.pushState()和history.replaceState(),和1个事件:window.onpopstate。hash + location.onhashchange
在后台管理系统中,一般都会采用权限管理。路由菜单数据都会保存到数据库中,在vue-router 2.2版本新增了一个router.addRoutes(routes)方法,即可用它来实现动态路由了
vue-router 默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。如果不想要很丑的 hash,我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。
原本想用动态路由的思路去做,按权限加载对应路由表,但是由于权限可以交叉(比如一个人可以同时是主题管理员和数据服务管理员),导致权限路由表还是得去做判断组合。于是放弃了这个思路,索性就在beforeEach里直接判断了。
使用vue-cli构建项目后,我们会在Router文件夹下面的index.js里面引入相关的路由组件,webpack在打包的时候会把整个路由打包成一个js文件,如果页面一多,会导致这个文件非常大,加载缓慢
query和params的区别,query相当于get请求,在页面跳转的时候,可以在地址栏看到请求参数,然而params则相当于post请求,参数不会在地址栏中显示。
当服务端接收到HTTP请求时,可以通过onRequest() 获取到url, pathname,query,及paramParams参数;为了解析这些数据需要使用url和querystring模块
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!