容易忽略的URL

栏目: 后端 · 前端 · 发布时间: 5年前

内容简介:众所周知,统一资源定位符(或称统一资源定位器/定位地址、URL地址等,英语:Uniform Resource Locator,常缩写为URL)标准格式:

众所周知, 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

总结

  • 标准的URL应该是 search + hash ,不要被当下各种框架欺骗,误以参数应该在hash后面拼接
  • URL中可以有多个问号,但为了便于理解,还是尽量避免这种写法
  • 避免上面尴尬问题的一个方法是 HTML5 Histroy 模式,感兴趣的同学可以关注并实践一下
  • 了解原理,了解设计模式,可以借鉴到平时开发项目中

参考文档


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

How to Design Programs

How to Design Programs

Matthias Felleisen、Robert Bruce Findler、Matthew Flatt、Shriram Krishnamurthi / The MIT Press / 2001-2-12 / 71.00美元

This introduction to programming places computer science in the core of a liberal arts education. Unlike other introductory books, it focuses on the program design process. This approach fosters a var......一起来看看 《How to Design Programs》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具