最近作项目才发现,我确实对 vue-router 太不熟悉了,都只了解个简单用法就开始搞了,原本很简单的问题,都搞不清楚。如今从新看一遍文档,从新梳理一下。html
说实话,路由我一直也就光顾着用,没认真思考过这个问题,仍是那次人家面试问了这个,我才反应过来是应该好好的了解一下了。前端
无刷新跳转页面,是单页应用的一大优点,用户体验好,加载速度快,vue 路由的跳转就是无刷新的,它有两种形式,能够在定义路由的时候经过 mode
字段去配置,若是不配置这个字段,那么默认使用的就是 hash
模式。 hash 模式,即经过在连接后添加 # + 路由名字,根据匹配这个字段的变化,触发 hashchange
事件,动态的渲染出页面。就有点相似像 a 连接用做页面上的锚点同样,不会刷新页面。vue
另一种方式,是 history
模式,也就是使用的浏览器的 history API,pushState
和 replaceState
。经过调用 pushState
操做浏览器的 history
对象,改变当前地址,同时结合window.onpopstate
监听浏览器的返回和前进事件,一样能够实现无刷新的跳转页面。replaceState
与 pushStete
不一样的就是,前者是替换一条记录,后者是添加一条记录。nginx
有关于 pushState
的用法,详见MDN 文档。这个 API 与 ajax
合起来构成的 pjax
技术,也是用于实现页面无刷新加载的一种方式,经常使用于 PC 长列表页面的翻页啥的~ history 相对于 hash 模式来讲,最大的好处就是没有讨厌的 # 符号,好比一样一个 list 页面,在 hash
模式下,url 连接表现为 http://yoursite.com/#/list
,看着就难受。在 history
模式下面,url 连接表现为 http://yoursite.com/list
,看着比较清爽~并且~相信作过微信公众号开发的都懂,这个该死的 # 有多烦人~在下面的应用场景里面我再讲下这个问题~面试
那么问题来了,既然 history 模式样子好看,功能也同样,为啥仍是用 hash 模式的人比较多【此处没有真凭实据,我瞎说的】?由于 history 模式,还须要服务端进行配置,不然刷新页面就会产生 404 错误。这里也比较好理解啦,由于咱们其实是使用的 pushState 操做页面的跳转,而不是真的去服务器请求另一个 list.html 文件,那按照 http://yoursite.com/#/list
这个路径,天然找不到啦~ajax
若是是 nginx 的服务器,在 location /
里面加上 try_files $uri $uri/ /index.html;
便可。这行代码表示:若是匹配不到静态资源的路径,就将重定向到 index 页面,这样就不会出错啦~由于须要找后端小哥哥修改服务器配置文件,若是本身没有彻底理解,两边又沟通不清楚的状况下,使用 history 模式的难度无疑就大了一些~不过也不是什么大问题~全看我的须要啦哈哈~算法
页面参数无非就两种,query 和 params,params 是以 /params
的形式表如今 url 上,而 query 是以 ?query=query1
这种形式表如今 url 上,此外,使用 params 参数还须要配置到路由定义上,否则不会展现在 url 上,而且刷新就会消失。vue-router
这个比较简单,须要注意的地方就是:若是传 params 参数,不能使用 path
字段跳转,不然没效果。而 query 参数则没有这个限制,使用 name
和 path
字段均可以。 这个虽然简单!可是必定要本身操做一遍才记得住啊。。反正我是早就看到,可是一直记混了~~从新用 demo 写了一遍才记住~并且别人说的也不必定就是对的,仍是要本身实验一遍才知道呢。╮(╯▽╰)╭编程
vue 路由的跳转分红两种,一种是声明式,使用<router-link>
声明跳转,to
属性定义跳转的参数。另外一种是编程式,使用 router.go()
、router.push()
、router.replace()
方法进行跳转,go
方法就是与浏览器的history
api 的方法相同,能够进行返回上一页等操做。segmentfault
push
方法和replace
方法的区别在于,前者会把当前页面加入 history 记录里面,能够经过history.go(-1)
回到这个页面。而replace
方法则会在 history 记录里面替换掉当前记录,若是你在跳转后的新页面返回上一页,它不会回到跳转前的页面,会回到上上个页面,若是上上个页面没有记录,则不会跳转。
vue 路由守卫分为三种,一种是全局的路由守卫,一般在实例化路由以后设置,来作一些通用的路由操做,它全部的路由跳转都会执行的操做;一种是单个路由独享的守卫,在单个路由定义的时候进行设置,全部跳转这个路由都会执行;另一种就是组件内的守卫,只在组件内生效。
全局路由守卫类型:
router.beforeEach(to, from, next)
router.afterEach(to, from, next)
路由独享的守卫:
beforeEnter(to, from, next)
组件独享的守卫:
beforeRouteEnter(to, from, next)
beforeRouteUpdate(to, from, next)
—— 动态参数路径改变时,组件实例被复用的时候调用。beforeRouteLeave(to, from, next)
—— 导航离开组件所在路由时被调用。最开始路由跳转我都是用 push()
比较多,或者用 go()
作返回,不多用到过 replace()
,后来在业务需求下翻文档才发现这个漏掉的 API。简单来讲,当你须要从A页面跳转到B页面,再跳转到C页面,而后在C页面返回,能直接返回到A页面。那么在B页面跳转C页面的时候,使用replace()
方法进行跳转便可。
beforeEach()
方法里面添加一个判断,获取路由的 meta 字段,动态的改变页面的 title。// router.js
{
path: '/index',
name: 'index',
meta: {
title: '首页'
}
}
// main.js
router.beforeEach(to, from, next){
if(to.meta.title){
document.title = to.meta.title
}
next() // 这个方法必须调用 否则路由不会跳转
}
复制代码
在作微信受权跳转的时候,hash 模式下连接里面带有 # 号可能会致使重定向跳转失败,使用 encodeURIComponent 把页面地址处理以后,再传入。
let _url = encodeURIComponent(location.href)
location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${this.appid}&redirect_uri=${_url}&response_type=code&scope=snsapi_base&state=#wechat_redirect`
复制代码
前端获取 wxconfig 比较简单,主要的操做都在后端,前端只须要传一个 url 参数,由后端去获取 config 的参数,回传给前端。前端拿到参数后,调用 wx.config
方法。
let url = location.href.split('#')[0]
http.get('weixin/config',{
params:{
url: encodeURIComponent(url)
}
})
.then(res=>{
wx.config({
beta: true, // 必须这么写,不然wx.invoke调用形式的jsapi会有问题
debug: false, // 开启调试模式,调用的全部api的返回值会在客户端alert出来,若要查看传入的参数,能够在pc端打开,参数信息会经过log打出,仅在pc端时才会打印。
appId: res.data.appId, // 必填,企业微信的corpID
timestamp: res.data.timestamp, // 必填,生成签名的时间戳
nonceStr: res.data.nonceStr, // 必填,生成签名的随机串
signature: res.data.signature,// 必填,签名,见 附录-JS-SDK使用权限签名算法
jsApiList: ['scanQRCode'] // 必填,须要使用的JS接口列表,凡是要调用的接口都须要传进来
})
// 检测微信
wx.error(function(res){
// config信息验证失败会执行error函数,如签名过时致使验证失败,具体错误信息能够打开config的debug模式查看,也能够在返回的res参数中查看,对于SPA能够在这里更新签名。
console.log('错误信息====',res)
})
})
复制代码
在单页应用上面,若是直接把百度统计的代码加到 html 不作任何处理的话,是统计不到每一个页面的访问量的,因此把添加 js 和 监听跳转页面的代码都写到 main.js 里面去。
// 添加百度统计 先判断是生产环境仍是开发环境 若是是开发环境 不用添加
if (process.env.NODE_ENV !== 'development') {
let _hmt = _hmt || [];
window._hmt = _hmt; // 必须把_hmt挂载到window下,不然找不到
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?yourappid";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})()
}
router.beforeEach(to, from, next){
// 添加百度统计代码 先判断是生产环境仍是开发环境
if (process.env.NODE_ENV !== 'development') {
// 添加页面统计
if (_hmt) {
if (to.path) {
_hmt.push(['_trackPageview', '/#' + to.fullPath]);
}
}
}
}
复制代码
参考文档: segmentfault.com/a/119000001…
www.jianshu.com/p/febd38110…