原理
前端路由是直接找到与地址匹配的一个组件或对象并将其渲染出来。改变浏览器地址而不向服务器发出请求
有两种方式:
1. 在地址中加入#以欺骗浏览器,地址的改变是由于正在进行页内导航
2. 使用H5的window.history功能,使用URL的Hash来模拟一个完整的URL。
两种模式比较
一般的需求场景中,hash模式与history模式是差不多的,根据MDN的介绍,调用history.pushState()相比于直接修改hash主要有以下优势:pushState设置的新url可以是与当前url同源的任意url,而hash只可修改#后面的部分,故只可设置与当前同文档的url
pushState设置的新url可以与当前url一模一样,这样也会把记录添加到栈中,而hash设置的新值必须与原来不一样才会触发记录添加到栈中
pushState通过stateObject可以添加任意类型的数据记录中,而hash只可添加短字符串
pushState可额外设置title属性供后续使用
history模式的问题
对于单页应用来说,理想的使用场景是仅在进入应用时加载index.html,后续在的网络操作通过ajax完成,不会根据url重新请求页面,但是如果用户直接在地址栏中输入并回车,浏览器重启重新加载等特殊情况。hash模式仅改变hash部分的内容,而hash部分是不会包含在http请求中的(hash带#):
oursite.com/#/user/id //如请求,只会发送http://oursite.com/ 所以hash模式下遇到根据url请求页面不会有问题
而history模式则将url修改的就和正常请求后端的url一样(history不带#)
oursite.com/user/id 如果这种向后端发送请求的话,后端没有配置对应/user/id的get路由处理,会返回404错误。
官方推荐的解决办法是在服务端增加一个覆盖所有情况的候选资源:如果
URL匹配不到任何静态资源,则应该返回同一个index.html页面,这个页面就是你app依赖的页面。同时这么做以后,服务器就不再返回404错误页面,因为对于所有路径都会返回index.html文件。为了避免这种情况,在Vue应用里面覆盖所有的路由情况,然后在给出一个404页面。或者,如果是用Node.js作后台,可以使用服务端的路由来匹配URL,当没有匹配到路由的时候返回404,从而实现fallback。
Vue-Router跳转
在vue项目中,往往会遇到这样的情况,就是要实现在一文章列表中,点击其中一条跳转到下个页面,然后将这一条的相关数据带到下个页面中显示,无论点哪一条都是跳到相同的页面结构(下一个页面的页面使用的组件是一样的),只是填的数据不一样,这个时候就需要实现跳转的时候一起把参数携带过去。
单个参数传递
比如下面的例子
<template>
<div class="template">
<!--点击文章列表跳转到相应的文章页面-->
<ul>
<li v-for="(article_task,index) in tasks">
<!--使用v-bind动态绑定id传递给目标路径-->
<!--注意: 这里携带了了article_task的一个参数id-->
<router-link tag="a" :to="{path:'/articleTask',query:{id:article_task.id}}">
<div class="article-render">
<span>{{index+1}}.</span>
<span>{{article_task.title}}</span>
<span>
{{article_task.content}}%
</span>
</div>
</router-link>
</li>
</ul>
</div>
</template>
但是:上面的的router-link传递一个一个参数id,当我们需要传递多个参数的时候应该怎么办呢,很简单,只需要将query的参数用逗号隔开就好了
多个参数传递
<router-link tag="a"
:to="{
path:'/articleTask',
query:{id:article_task.id,title:article_task.title,content:article_task.content}
}">
</router-link>
但是问题,又来了。。。。。代码这样写贼鸡儿多,万一写错一个那我岂不是文章不现实了,所以还有一个更简单的办法
优化多个参数传递
就是将要传的参数以一个object传递,在跳转的页面中created中,接收这个object
<router-link tag="a" :to="{path:'/articleTask',query{arry:article_task}}"></router-link>
传递参数可以,怎么接收参数呢?在目标组件里接收参数,只需要在created()钩子中接收即可,实现如下:
<script>
export default {
data() {
return {
}
},
created() {
//单个参数传递的时候
this.id = this.$route.query.id;//获取上个页面传递的id,在下面获取数据的时候先提交id
//这边接收上个组件传递过来的arry数组,赋值给data中定义的articleTask
this.articleTask = this.$route.query.arry;
},
}
</script>
<router-link tag="a" :to="{path:'/articleTask',query{id:article_task.id}}">
vue 跳转的两种写法
声明式的写法
上面的写法是声明式的写法,直接写在组件里面template里面
表示目标路由的链接。当被点击后,内部会立刻把to的值传到router.push(),所以这个值可以是一个字符串或者是描述目标位置的对象。
router.push(location)想要导航到不同的URL,则使用router.push方法。这个方法会向history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的URL。
编程式的写法
编程式的写法router.push(location) 点击一个标签触发一个事件,在methods中对应的事件中写入this.$router.push(.....)
const router = new VueRouter({
routes: [
// 下面的对象就是路由记录
{ path: '/foo', component: Foo,
children: [
// 这也是个路由记录
{ path: 'bar', component: Bar }
]
}
]
})
编程式写法的几种方式
字符串
this.$router.push('login')
对象
this.$router.push({path: '/login?url=' + this.$route.path});
命名的路由
this.$router.push({ name: 'login', params: { userId: 123 }})
带查询参数,变成/foo/bar?selected=1
this.$router.push({path: '/foo/bar', query: {selected: "1"}});
params传参和query传参有什么区别
query要用path来引入,params要用name来引入,而params传参配置的是name,在params中配置path无效接收参数都是类似的,分别是this.$route.query.name和this.$route.params.name。
query更加类似于我们ajax中get传参,params则类似于post,说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示
query在路由配置不需要设置参数,而params必须设置
query传递的参数会显示在地址栏中
params传参刷新会无效,但是query会保存传递过来的值,刷新不变 ;
this.$router.replace()
用法参考this.$router.push()
设置replace属性(默认值:false)的话,当点击时,会调用 router.replace()而不是 router.push(),于是导航后不会留下history 记录。即使点击返回按钮也不会回到这个页面。
加上replace: true后,它不会向history添加新记录,而是跟它的方法名一样 —— 替换掉当前的history记录。
本文使用 mdnice 排版