摘要:场景再现众所周知,有三种模式,一般的前端项目中会选择模式进行开发,最近做了一个运营活动就是基于的模式进行开发的。项目注册了两个路由抽象出来的入口页面需要参数,所以提供浏览器里输入回车后,页面自动增加一个变为。
场景再现
众所周知,vue-router有三种模式 :hash、html5、abstract , 一般的前端项目中会选择hash模式进行开发,最近做了一个运营活动就是基于vue-router的hash模式进行开发的。
项目注册了两个路由(抽象出来的Demo)
var router = new VueRouter({ routes: [{ name: "index", path: "", component: indexcomponent },{ name: "demo", path: "/demo", component: democomponent }] });
入口页面需要参数,所以提供URL:https://www.xxx.com?from=weixin, 浏览器里输入URL回车后,页面自动增加一个#/变为https://www.xxx.com?from=weixin#/。
index页面中一个按钮点击后跳转demo,同时想携带index中获取的参数,看API选择了如下方式,结果URL变成了:https://www.xxx.com?from=weixin#/test?userId=123
router.push({ path: "demo", query: { plan: "private" } })产生质疑
URL有什么标准?(上面Demo页面跳转后URL看起来怪怪的)
vue-router是如何控制URL的?
质疑探究 URL标准统一资源定位符(或称统一资源定位器/定位地址、URL地址等,英语:Uniform Resource Locator,常缩写为URL)
标准格式:scheme:[//authority]path[?query][#fragment]
==例子==
下图展示了两个 URI 例子及它们的组成部分。
URL中的『?』『#』hierarchical part ┌───────────────────┴─────────────────────┐ authority path ┌───────────────┴───────────────┐┌───┴────┐abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
└┬┘ └───────┬───────┘ └────┬────┘ └┬┘ └─────────┬─────────┘ └──┬──┘
scheme user information host port query fragmenturn:example:mammal:monotreme:echidna
└┬┘ └──────────────┬───────────────┘
scheme path
『?』
路径与参数分隔符
浏览器只识别url中的第一个『?』,后面的会当做参数处理
『#』
『#』一般是页面内定位用的,如我们最熟悉不过的锚点定位
浏览器可以通过『onhashchange』监听hash的变化
http请求中不包含#
Request Headers中的Referer不包含#
改变#不触发网页重载
url中#后面出现的任何字符都会被截断。(http://www.xxx.com/?color=#fff发出请求是:/color=)
改变#会改变history
window.location.hash读取#值
URL读取和操作URL读取和操作涉及location和history两个对象,具体如下:
location API :
属性
href = protocol + hostName + port + pathname + search + hash
host
origin
方法
assign
href
replace ,不记录history
reload
history API:
方法
back()
forward()
go()
H5新增API
pushState()
replaceState()
popstate监听变化
vue-router路由实现浅析初始化router的时候,根据指定的mode选择路由实现,当然mode判断有一定逻辑和兼容策略
switch (mode) { case "history": this.history = new HTML5History(this, options.base) break case "hash": this.history = new HashHistory(this, options.base, this.fallback) break case "abstract": this.history = new AbstractHistory(this, options.base) break default: if (process.env.NODE_ENV !== "production") { assert(false, `invalid mode: ${mode}`) } }
我们选择hash模式进行深入分析,对应HashHistory模块,该模块是history/hash.js实现的,当被调用的时候,对全局路由变化进行了监听
window.addEventListener(supportsPushState ? "popstate" : "hashchange", () => { ... })
同时hash.js中也实现了push等api方法的封装,我们以push为例,根据源码可以看出,它的实现是基于基类transitionTo的实现,具体如下:
push (location: RawLocation, onComplete?: Function, onAbort?: Function) { const { current: fromRoute } = this this.transitionTo(location, route => { pushHash(route.fullPath) handleScroll(this.router, route, fromRoute, false) onComplete && onComplete(route) }, onAbort) }
既然调用了transitionTo那么来看它的实现,获取参数后调用confirmTransition
transitionTo (location: RawLocation, onComplete?: Function, onAbort?: Function) { // 获取URL中的参数 const route = this.router.match(location, this.current) this.confirmTransition(route, () => { this.updateRoute(route) onComplete && onComplete(route) this.ensureURL() ... }) }
同时confirmTransition里实现了一个队列,顺序执行,iterator通过后执行next,进而志新pushHash(),实现页面hash改变,最终实现了${base}#${path}的连接
function getUrl (path) { const href = window.location.href const i = href.indexOf("#") const base = i >= 0 ? href.slice(0, i) : href return `${base}#${path}` } function pushHash (path) { if (supportsPushState) { pushState(getUrl(path)) } else { window.location.hash = path } }问题解决
https://www.xxx.com?from=weixin#/test?userId=123这个页面看起来感觉怪,是因为这个连接中几乎包含了所有的参数,而且hash里面还有一个问号,一个URL中多个问号的不常见
vue-router也是基于基本的URL操作来进行URL切换的,在基本基础上进行了封装。里面很多思路还是应该多学习借鉴的。比如实现的队列、继承的运用等
总结标准的URL应该是 search + hash ,不要被当下各种框架欺骗,误以参数应该在hash后面拼接
URL中可以有多个问号,但为了便于理解,还是尽量避免这种写法
避免上面尴尬问题的一个方法是 HTML5 Histroy 模式,感兴趣的同学可以关注并实践一下
了解原理,了解设计模式,可以借鉴到平时开发项目中
参考文档https://github.com/vuejs/vue-...
https://developer.mozilla.org...
https://en.wikipedia.org/wiki...
https://www.cnblogs.com/qingg...
http://www.cnblogs.com/qinggu...
https://segmentfault.com/p/12...
https://segmentfault.com/a/11...
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/52840.html
摘要:起因今天用打包的时候发现不加压缩居然比加上还要小,命令行分两次输入回车的时候是正常的。反复实验多次,打印也正常。拐回头看我们的代码我们来对比一下对错写法一个小失误,顺便附上我的翻版必究 起因 今天用webpack 打包的时候发现 不加 set NODE_ENV 压缩 居然比加上 set NODE_ENV 还要小,命令行 分两次输入 set NODE_ENV=production (回...
摘要:最近开始移动端页面的时候,被和坑了一把,于是决定对这两个对象进行一个全面的剖析。但出于隐私方面的原因,对象不再允许脚本访问已经访问过的实际。唯一保持使用的功能只有和方法。华为执行完之后,我们发现不能回退了,是不是就跟实现同样的效果了。 最近开始移动端页面的时候,被window.location和window.history坑了一把,于是决定对这两个对象进行一个全面的剖析。下面进行我们的...
摘要:和事件可用于处理。循环中的代码块将针对每个属性执行一次。返回值是被找到的值。是被视为节点树的。将新元素作为父元素的最后一个子元素进行添加。返回指定的属性值。把指定属性设置或修改为指定的值。年龄必须是与之间的数字。 JS JS DOM onload 和 onunload 事件会在用户进入或离开页面时被触发。onload 事件可用于检测访问者的浏览器类型和浏览器版本,并基于这些信息来加载网...
摘要:也就是说,在大多数情况下,他们只关注标签中的,而忽略标签周围的上下文。就算对于大多数正常使用浏览器的用户来说,人们也容易只被标签中的内容吸引,而忽略上下文。总之,保持标签中的关键字简洁是非常重要的。 什么是标签 官方定义是这样的: The HTML element (or anchor element) creates a hyperlink to other web pages,...
阅读 2960·2021-11-23 09:51
阅读 2766·2021-11-11 16:55
阅读 2827·2021-10-14 09:43
阅读 1376·2021-09-23 11:22
阅读 1018·2019-08-30 11:04
阅读 1637·2019-08-29 11:10
阅读 930·2019-08-27 10:56
阅读 3079·2019-08-26 12:01