资讯专栏INFORMATION COLUMN

容易忽略的URL

Richard_Gao / 1301人阅读

摘要:场景再现众所周知,有三种模式,一般的前端项目中会选择模式进行开发,最近做了一个运营活动就是基于的模式进行开发的。项目注册了两个路由抽象出来的入口页面需要参数,所以提供浏览器里输入回车后,页面自动增加一个变为。

场景再现

众所周知,vue-router有三种模式 :hashhtml5abstract , 一般的前端项目中会选择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 例子及它们的组成部分。

                hierarchical part
    ┌───────────────────┴─────────────────────┐
                authority               path
    ┌───────────────┴───────────────┐┌───┴────┐

abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
└┬┘ └───────┬───────┘ └────┬────┘ └┬┘ └─────────┬─────────┘ └──┬──┘
scheme user information host port query fragment

urn:example:mammal:monotreme:echidna
└┬┘ └──────────────┬───────────────┘
scheme path

URL中的『?』『#』

『?』

路径与参数分隔符

浏览器只识别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

相关文章

  • 容易忽略URL

    摘要:场景再现众所周知,有三种模式,一般的前端项目中会选择模式进行开发,最近做了一个运营活动就是基于的模式进行开发的。项目注册了两个路由抽象出来的入口页面需要参数,所以提供浏览器里输入回车后,页面自动增加一个变为。 场景再现 众所周知,vue-router有三种模式 :hash、html5、abstract , 一般的前端项目中会选择hash模式进行开发,最近做了一个运营活动就是基于vue-...

    CoyPan 评论0 收藏0
  • win 下 package.json 与 webpack 配置容易忽略一个坑

    摘要:起因今天用打包的时候发现不加压缩居然比加上还要小,命令行分两次输入回车的时候是正常的。反复实验多次,打印也正常。拐回头看我们的代码我们来对比一下对错写法一个小失误,顺便附上我的翻版必究 起因 今天用webpack 打包的时候发现 不加 set NODE_ENV 压缩 居然比加上 set NODE_ENV 还要小,命令行 分两次输入 set NODE_ENV=production (回...

    linkin 评论0 收藏0
  • JS中最容易被轻视对象----location和history

    摘要:最近开始移动端页面的时候,被和坑了一把,于是决定对这两个对象进行一个全面的剖析。但出于隐私方面的原因,对象不再允许脚本访问已经访问过的实际。唯一保持使用的功能只有和方法。华为执行完之后,我们发现不能回退了,是不是就跟实现同样的效果了。 最近开始移动端页面的时候,被window.location和window.history坑了一把,于是决定对这两个对象进行一个全面的剖析。下面进行我们的...

    xumenger 评论0 收藏0
  • w3school容易忽略东西

    摘要:和事件可用于处理。循环中的代码块将针对每个属性执行一次。返回值是被找到的值。是被视为节点树的。将新元素作为父元素的最后一个子元素进行添加。返回指定的属性值。把指定属性设置或修改为指定的值。年龄必须是与之间的数字。 JS JS DOM onload 和 onunload 事件会在用户进入或离开页面时被触发。onload 事件可用于检测访问者的浏览器类型和浏览器版本,并基于这些信息来加载网...

    shadowbook 评论0 收藏0
  • 标签<a>最佳实践

    摘要:也就是说,在大多数情况下,他们只关注标签中的,而忽略标签周围的上下文。就算对于大多数正常使用浏览器的用户来说,人们也容易只被标签中的内容吸引,而忽略上下文。总之,保持标签中的关键字简洁是非常重要的。 什么是标签 官方定义是这样的: The HTML element (or anchor element) creates a hyperlink to other web pages,...

    jsyzchen 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<