容易忽略的URL

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

内容简介:众所周知,统一资源定位符(或称统一资源定位器/定位地址、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 模式,感兴趣的同学可以关注并实践一下
  • 了解原理,了解设计模式,可以借鉴到平时开发项目中

参考文档


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

查看所有标签

猜你喜欢:

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

Building Websites with Joomla!

Building Websites with Joomla!

H Graf / Packt Publishing / 2006-01-20 / USD 44.99

This book is a fast paced tutorial to creating a website using Joomla!. If you've never used Joomla!, or even any web content management system before, then this book will walk you through each step i......一起来看看 《Building Websites with Joomla!》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

html转js在线工具
html转js在线工具

html转js在线工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具