/* @flow */import { warn } from './warn'//判断字符为 !'()* 的正则表达式。
const encodeReserveRE = /[!'()*]/g
/* 1、c.charCodeAt(0) 获取字符的 ascii 编码,返回的是数字。2、number.toString(16) 返回 16 进制数字编码的字符串形式。3、!'()* 转换成的形式为 %21%27%28%29%2a。*/
const encodeReserveReplacer = (c) => '%' + c.charCodeAt(0).toString(16)
//匹配 %2c
const commaRE = /%2C/g// fixed encodeURIComponent which is more conformant to RFC3986:
// - escapes [!'()*]  逃逸 [!'()*]  字符。
// - preserve commas  保护逗号
/*encode() 对 str 进行编码。对 url 上不能使用的特殊字符进行编码转换。
*/
const encode = (str) =>//对字符串进行编码转化 (url上不能有特殊字符。)encodeURIComponent(str)//另外将 [!'()*] 转换成  %21%27%28%29%2a 的形式。.replace(encodeReserveRE, encodeReserveReplacer)//将 %2c 替换成 , (2c 就是 44 的十六进制表示。 44 的 ascii 符号对应的就是 ,).replace(commaRE, ',')/*decode() 对 str 进行特殊字符解码。
*/
export function decode(str: string) {try {// encodeURIComponent, decodeURIComponent 常用于对 url 进行编码解码,用于处理 url 上不能使用的特殊字符。return decodeURIComponent(str)} catch (err) {//如果发生异常,且不是生产环境,则直接警告提示。if (process.env.NODE_ENV !== 'production') {warn(false, `Error decoding "${str}". Leaving it intact.`)}}//返回字符串。return str
}/*resolveQuery() 将所有的 query 统一到一个对象中。
*/
export function resolveQuery(//url 上携带的 query。query: ?string,//{ path: xxx, query: {xxx} } 上的 query。extraQuery: Dictionary<string> = {},//router.options.parseQuery  这是个函数。_parseQuery: ?Function
): Dictionary<string> {//如果用户配置了 parseQuery() 函数,则使用用户配置的;否则使用默认的 parseQuery() 函数。const parse = _parseQuery || parseQuerylet parsedQuerytry {//解析成一个 Object 对象。//  { key1=value1, key2=[value2,value3] }parsedQuery = parse(query || '')} catch (e) {//如果是非生产环境,解析出现异常,则报出警告。process.env.NODE_ENV !== 'production' && warn(false, e.message)//且将 parsedQuery 设置为空对象。parsedQuery = {}}//extraQuery 是通过 push() 或者 replace() 的时候指定的 query 参数对象。// <link-view :to={path:'xxxx', query: {xxxx}}></link-view>// this.$router.push( { path: "xxx", query: {xxxxxx} } )for (const key in extraQuery) {//遍历 extraQuery 对象并且获取 value。const value = extraQuery[key]parsedQuery[key] = Array.isArray(value)? //如果 value 是数组,则对每个元素进行处理;///如果元素是基础类型数据,则转为字符串;否则原样返回。并添加到 parsedQuery 对象中。value.map(castQueryParamValue): //如果 value 是基础类型数据,则转为字符串;否则原样返回。并添加到 parsedQuery 对象中。castQueryParamValue(value)}//返回一个合并了 url 中 query 字符串, 以及 query:{} 数据的对象。return parsedQuery
}/*如果 value == null,则返回 null。如果 value 是不为 null 的对象,则返回 value 对象。如果 value 不是对象,则转化为字符串。
*/
const castQueryParamValue = (value) =>value == null || typeof value === 'object' ? value : String(value)/*parseQuery() 用于将 key=value&key=value 解析成对象。{ key: value, key1:[value2,value3] }
*/
// query 是 ?到 # 之间的字符串。
function parseQuery(query: string): Dictionary<string> {const res = {}//去除空格,以及 ? # & 开头的字符。query = query.trim().replace(/^(\?|#|&)/, '')//如果 query 不存在,则直接返回 {}.if (!query) {return res}//按照 & 切分 key=value&key1=value2... 成一个数组,并且依次遍历。query.split('&').forEach((param) => {/*param 根据 = 切分,且将第一个 = 左边的内容当作 key,后面的 = 的都是值。*///去掉 key=value 中的 \ 字符, 并且按照 = 切分。const parts = param.replace(/\+/g, ' ').split('=')//parts.shift() 获取 = 左边的字符串。此时 parts 的长度减1.const key = decode(parts.shift())//将第一个等号后面的内容又拼成一个字符串当作val值。//如果没有值,则默认为 null。const val = parts.length > 0 ? decode(parts.join('=')) : null//如果 res[key] 不存在if (res[key] === undefined) {//则表示是key不重复,就是单个的 key=value 数据。res[key] = val} else if (Array.isArray(res[key])) {//如果 res[key] 已经存在,且是一个数组,那么 val 数组存储该值。//这种情形的数据为: key=value&key=value2&key=value3;res[key].push(val)} else {//如果 res[key] 已经存在,则数据是数组的形式。//这种情形的数据为: key=value&key=value2res[key] = [res[key], val]}})//将字符串形式 key=value&key1=value1&key1=value2//转化为对象形式: {//    key: value,//    key1: [value1, value]//}return res
}/*stringifyQuery() 将 query 参数进行序列化成字符串。假设 obj = {user: 'mengze',favor: ['play game', 'program']}*/
export function stringifyQuery(obj: Dictionary<string>): string {/*** 如果 obj 不为空。*/const res = obj? // [].map(()=>return {}) 得到一个对象所有 key 的数组。Object.keys(obj)//通过 arrya.map() 之后,返回的依然是个数组。.map((key) => {//获取obj对象属性的值。const val = obj[key]//如果val为undefined,数组记录元素的值为 ''if (val === undefined) {return ''}//如果val为 null,则进行特殊字符转码处理。 数组记录元素的值为 转码之后的null。if (val === null) {return encode(key)}//如果 val 是数组,比如 user: ["mengze", "xiaomeng", "xiaoze"];// 会将数组转化为 user=mengze&user=xiaomeng&user=xiaoze 的形式。// 数组记录元素的值为 "user=mengze&user=xiaomeng&user=xiaoze"if (Array.isArray(val)) {const result = []val.forEach((val2) => {//如果元素是 undefined, 直接丢弃。if (val2 === undefined) {return}//如果元素是 null,则进行特殊字符转码处理。if (val2 === null) {result.push(encode(key))} else {//如果是正常的数据, 就改写成 key=value1&key=value2... 的形式。//url 的 query 中传递数组的形式就是:  user=mengze&user=xiaoze 的形式。result.push(encode(key) + '=' + encode(val2))}})//将 key-value 数组转化为 & 间隔的字符串形式。return result.join('&')}//将 val 是普通字符串的转化为 key=value 形式字符串。return encode(key) + '=' + encode(val)})//将数组元素为 '' 的情形过滤掉。为 null 的情形不会被过滤。.filter((x) => x.length > 0)//将 key=value 情形的数组,组成 query 字符串的形式。.join('&'): null//如果 res 不为空,则拼接一个问号。return res ? `?${res}` : ''
}

vue-router3 源码注释系列 /src/util/query.js相关推荐

  1. vue-router3 源码注释系列 /src/util/scroll.js

    /* @flow */import type Router from '../index' import { assert } from './warn' //getStateKey: 用于获取时间戳 ...

  2. vue-router3 源码注释系列 /src/util/push-state.js

    /* @flow *///用于判断是否是浏览器环境 import { inBrowser } from './dom' //保存滚动的位置(x,y). import { saveScrollPosit ...

  3. vue-router3 源码注释系列 /src/util/path.js

    /* @flow *//*** resolvePath(): 解析路径* 第一个参数: 相对路径,要跳转路径的 pathname.* 第二个参数: 基准路径.* 第三个参数: 是否需要拼接基准地址.* ...

  4. vue源码注释系列 /src/module/module.js

    import { forEachValue } from "../util";// Base data struct for store's module, package wit ...

  5. three.js 源码注释(一)./Three.js

    商域无疆 (http://blog.csdn.net/omni360/) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:商域无疆 -  本博客专注于 敏捷开发 ...

  6. vue-router3源码注视系列 /src/index.js

    /* @flow *///install: vue.use( VueRouter ) 时调用的 install() 方法. import { install } from './install' // ...

  7. vue 计算属性_lt;Vue 源码笔记系列6gt;计算属性 computed 的实现

    1. 前言 原文发布在语雀: <Vue 源码笔记系列6>计算属性 computed 的实现 · 语雀​www.yuque.com 上一章我们已经学习过 watch,这一章就来看一下计算属性 ...

  8. vue如何让一句代码只执行一次_lt;Vue 源码笔记系列4gt;异步更新队列与$nextTick...

    1. 前言 原文发布在语雀: <Vue 源码笔记系列4>异步更新队列与$nextTick · 语雀​www.yuque.com 上一章我们讲到了修改数据是如何触发渲染函数的观察者,最终调用 ...

  9. vue源码分析系列二:$mount()和new Watcher()的执行过程

    续vue源码分析系列一:new Vue的初始化过程 在initMixin()里面调用了$mount() if (vm.$options.el) {vm.$mount(vm.$options.el);/ ...

最新文章

  1. jni返回byte[]
  2. Cookie与Session的区别
  3. 【PAT乙级】1056 组合数的和 (15 分)
  4. jaxws-webservice编程续
  5. Navcat:1251 client does not support ...问题
  6. 梦回JavaScript--数据类型之undefined
  7. 数据结构与算法-- 广度优先打印二叉树
  8. Mysql存储结构B树与B+树与索引
  9. 一种单独适配于NER的数据增强方法:DAGA
  10. Linux 修改IP及虚拟网卡配置详解
  11. 图像处理之基础---特征向量的 几何意义
  12. Turbo码:3GPP TS 36.212
  13. quartz2.3.0(六)job任务异常处理方式
  14. CSS属性:display详解
  15. WPF案例 (五) 对控件界面使用倒影
  16. MAC使用CodeSign查看已签名的文件的数字签名情况
  17. OSD仿真_MFC程序01
  18. 虚拟大师怎么修改手机_[Android] 新版手机虚拟大师VMOS Pro超精简无广告2秒启动...
  19. 计算机思维的概念知识点,思维的基本特征知识点的理解
  20. C语言上机复习(一)文件操作

热门文章

  1. Android-MVP模式详解,经典好文
  2. (python3)kaggle上matplotlib显示不了中文(title是框,坐标也是框)完全解决.md
  3. 2015-07-12
  4. 五一在家宅5天?前端开发工程师必读书单送给你!(文末大彩蛋!)
  5. 软件测试常见的问题(理论题)
  6. 如何使用并行计算来加速并行计算中的分布式计算优化?
  7. Android OTA 升级
  8. java逻辑运算符试题_Java逻辑运算符(、||和!)
  9. Windows 7下安装IIS 及配置 ASP详解
  10. 高精度倾角传感器的应用