You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

724 lines
22 KiB

2 months ago
  1. import {
  2. number as testNumber,
  3. array as testArray,
  4. empty as testEmpty
  5. } from './test'
  6. import { round } from './digit.js'
  7. import config from '../config/config';
  8. /**
  9. * @description 如果value小于min取min如果value大于max取max
  10. * @param {number} min
  11. * @param {number} max
  12. * @param {number} value
  13. */
  14. export function range(min = 0, max = 0, value = 0) {
  15. return Math.max(min, Math.min(max, Number(value)))
  16. }
  17. /**
  18. * @description 用于获取用户传递值的px值 如果用户传递了"xxpx"或者"xxrpx"取出其数值部分如果是"xxxrpx"还需要用过uni.rpx2px进行转换
  19. * @param {number|string} value 用户传递值的px值
  20. * @param {boolean} unit
  21. * @returns {number|string}
  22. */
  23. export function getPx(value, unit = false) {
  24. if (testNumber(value)) {
  25. return unit ? `${value}px` : Number(value)
  26. }
  27. // 如果带有rpx,先取出其数值部分,再转为px值
  28. if (/(rpx|upx)$/.test(value)) {
  29. return unit ? `${uni.upx2px(parseInt(value))}px` : Number(uni.upx2px(parseInt(value)))
  30. }
  31. return unit ? `${parseInt(value)}px` : parseInt(value)
  32. }
  33. /**
  34. * @description 进行延时以达到可以简写代码的目的 比如: await uni.$u.sleep(20)将会阻塞20ms
  35. * @param {number} value 堵塞时间 单位ms 毫秒
  36. * @returns {Promise} 返回promise
  37. */
  38. export function sleep(value = 30) {
  39. return new Promise((resolve) => {
  40. setTimeout(() => {
  41. resolve()
  42. }, value)
  43. })
  44. }
  45. /**
  46. * @description 运行期判断平台
  47. * @returns {string} 返回所在平台(小写)
  48. * @link 运行期判断平台 https://uniapp.dcloud.io/frame?id=判断平台
  49. */
  50. export function os() {
  51. return uni.getSystemInfoSync().platform.toLowerCase()
  52. }
  53. /**
  54. * @description 获取系统信息同步接口
  55. * @link 获取系统信息同步接口 https://uniapp.dcloud.io/api/system/info?id=getsysteminfosync
  56. */
  57. export function sys() {
  58. return uni.getSystemInfoSync()
  59. }
  60. /**
  61. * @description 取一个区间数
  62. * @param {Number} min 最小值
  63. * @param {Number} max 最大值
  64. */
  65. export function random(min, max) {
  66. if (min >= 0 && max > 0 && max >= min) {
  67. const gab = max - min + 1
  68. return Math.floor(Math.random() * gab + min)
  69. }
  70. return 0
  71. }
  72. /**
  73. * @param {Number} len uuid的长度
  74. * @param {Boolean} firstU 将返回的首字母置为"u"
  75. * @param {Nubmer} radix 生成uuid的基数(意味着返回的字符串都是这个基数),2-二进制,8-八进制,10-十进制,16-十六进制
  76. */
  77. export function guid(len = 32, firstU = true, radix = null) {
  78. const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('')
  79. const uuid = []
  80. radix = radix || chars.length
  81. if (len) {
  82. // 如果指定uuid长度,只是取随机的字符,0|x为位运算,能去掉x的小数位,返回整数位
  83. for (let i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix]
  84. } else {
  85. let r
  86. // rfc4122标准要求返回的uuid中,某些位为固定的字符
  87. uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'
  88. uuid[14] = '4'
  89. for (let i = 0; i < 36; i++) {
  90. if (!uuid[i]) {
  91. r = 0 | Math.random() * 16
  92. uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]
  93. }
  94. }
  95. }
  96. // 移除第一个字符,并用u替代,因为第一个字符为数值时,该guuid不能用作id或者class
  97. if (firstU) {
  98. uuid.shift()
  99. return `u${uuid.join('')}`
  100. }
  101. return uuid.join('')
  102. }
  103. /**
  104. * @description 获取父组件的参数因为支付宝小程序不支持provide/inject的写法
  105. this.$parent在非H5中可以准确获取到父组件但是在H5中需要多次this.$parent.$parent.xxx
  106. 这里默认值等于undefined有它的含义因为最顶层元素(组件)的$parent就是undefined意味着不传name
  107. (默认为undefined)就是查找最顶层的$parent
  108. * @param {string|undefined} name 父组件的参数名
  109. */
  110. export function $parent(name = undefined) {
  111. let parent = this.$parent
  112. // 通过while历遍,这里主要是为了H5需要多层解析的问题
  113. while (parent) {
  114. // 父组件
  115. if (parent.$options && parent.$options.name !== name) {
  116. // 如果组件的name不相等,继续上一级寻找
  117. parent = parent.$parent
  118. } else {
  119. return parent
  120. }
  121. }
  122. return false
  123. }
  124. /**
  125. * @description 样式转换
  126. * 对象转字符串或者字符串转对象
  127. * @param {object | string} customStyle 需要转换的目标
  128. * @param {String} target 转换的目的object-转为对象string-转为字符串
  129. * @returns {object|string}
  130. */
  131. export function addStyle(customStyle, target = 'object') {
  132. // 字符串转字符串,对象转对象情形,直接返回
  133. if (testEmpty(customStyle) || typeof(customStyle) === 'object' && target === 'object' || target === 'string' &&
  134. typeof(customStyle) === 'string') {
  135. return customStyle
  136. }
  137. // 字符串转对象
  138. if (target === 'object') {
  139. // 去除字符串样式中的两端空格(中间的空格不能去掉,比如padding: 20px 0如果去掉了就错了),空格是无用的
  140. customStyle = trim(customStyle)
  141. // 根据";"将字符串转为数组形式
  142. const styleArray = customStyle.split(';')
  143. const style = {}
  144. // 历遍数组,拼接成对象
  145. for (let i = 0; i < styleArray.length; i++) {
  146. // 'font-size:20px;color:red;',如此最后字符串有";"的话,会导致styleArray最后一个元素为空字符串,这里需要过滤
  147. if (styleArray[i]) {
  148. const item = styleArray[i].split(':')
  149. style[trim(item[0])] = trim(item[1])
  150. }
  151. }
  152. return style
  153. }
  154. // 这里为对象转字符串形式
  155. let string = ''
  156. if (typeof customStyle === 'object') {
  157. customStyle.forEach((val, i) => {
  158. // 驼峰转为中划线的形式,否则css内联样式,无法识别驼峰样式属性名
  159. const key = i.replace(/([A-Z])/g, '-$1').toLowerCase()
  160. string += `${key}:${val};`
  161. })
  162. }
  163. // 去除两端空格
  164. return trim(string)
  165. }
  166. /**
  167. * @description 添加单位如果有rpxupx%px等单位结尾或者值为auto直接返回否则加上px单位结尾
  168. * @param {string|number} value 需要添加单位的值
  169. * @param {string} unit 添加的单位名 比如px
  170. */
  171. export function addUnit(value = 'auto', unit = '') {
  172. if (!unit) {
  173. unit = config.unit || 'px'
  174. }
  175. value = String(value)
  176. // 用uView内置验证规则中的number判断是否为数值
  177. return testNumber(value) ? `${value}${unit}` : value
  178. }
  179. /**
  180. * @description 深度克隆
  181. * @param {object} obj 需要深度克隆的对象
  182. * @returns {*} 克隆后的对象或者原值不是对象
  183. */
  184. export function deepClone(obj) {
  185. // 对常见的“非”值,直接返回原来值
  186. if ([null, undefined, NaN, false].includes(obj)) return obj
  187. if (typeof obj !== 'object' && typeof obj !== 'function') {
  188. // 原始类型直接返回
  189. return obj
  190. }
  191. const o = testArray(obj) ? [] : {}
  192. for (const i in obj) {
  193. if (obj.hasOwnProperty(i)) {
  194. o[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i]
  195. }
  196. }
  197. return o
  198. }
  199. /**
  200. * @description JS对象深度合并
  201. * @param {object} target 需要拷贝的对象
  202. * @param {object} source 拷贝的来源对象
  203. * @returns {object|boolean} 深度合并后的对象或者false入参有不是对象
  204. */
  205. export function deepMerge(targetOrigin = {}, source = {}) {
  206. let target = deepClone(targetOrigin)
  207. if (typeof target !== 'object' || typeof source !== 'object') return false
  208. for (const prop in source) {
  209. if (!source.hasOwnProperty(prop)) continue
  210. if (prop in target) {
  211. if (source[prop] == null) {
  212. target[prop] = source[prop]
  213. }else if (typeof target[prop] !== 'object') {
  214. target[prop] = source[prop]
  215. } else if (typeof source[prop] !== 'object') {
  216. target[prop] = source[prop]
  217. } else if (target[prop].concat && source[prop].concat) {
  218. target[prop] = target[prop].concat(source[prop])
  219. } else {
  220. target[prop] = deepMerge(target[prop], source[prop])
  221. }
  222. } else {
  223. target[prop] = source[prop]
  224. }
  225. }
  226. return target
  227. }
  228. /**
  229. * @description JS对象深度合并
  230. * @param {object} target 需要拷贝的对象
  231. * @param {object} source 拷贝的来源对象
  232. * @returns {object|boolean} 深度合并后的对象或者false入参有不是对象
  233. */
  234. export function shallowMerge(target, source = {}) {
  235. if (typeof target !== 'object' || typeof source !== 'object') return false
  236. for (const prop in source) {
  237. if (!source.hasOwnProperty(prop)) continue
  238. if (prop in target) {
  239. if (source[prop] == null) {
  240. target[prop] = source[prop]
  241. }else if (typeof target[prop] !== 'object') {
  242. target[prop] = source[prop]
  243. } else if (typeof source[prop] !== 'object') {
  244. target[prop] = source[prop]
  245. } else if (target[prop].concat && source[prop].concat) {
  246. target[prop] = target[prop].concat(source[prop])
  247. } else {
  248. target[prop] = shallowMerge(target[prop], source[prop])
  249. }
  250. } else {
  251. target[prop] = source[prop]
  252. }
  253. }
  254. return target
  255. }
  256. /**
  257. * @description error提示
  258. * @param {*} err 错误内容
  259. */
  260. export function error(err) {
  261. // 开发环境才提示,生产环境不会提示
  262. if (process.env.NODE_ENV === 'development') {
  263. console.error(`uView提示:${err}`)
  264. }
  265. }
  266. /**
  267. * @description 打乱数组
  268. * @param {array} array 需要打乱的数组
  269. * @returns {array} 打乱后的数组
  270. */
  271. export function randomArray(array = []) {
  272. // 原理是sort排序,Math.random()产生0<= x < 1之间的数,会导致x-0.05大于或者小于0
  273. return array.sort(() => Math.random() - 0.5)
  274. }
  275. // padStart 的 polyfill,因为某些机型或情况,还无法支持es7的padStart,比如电脑版的微信小程序
  276. // 所以这里做一个兼容polyfill的兼容处理
  277. if (!String.prototype.padStart) {
  278. // 为了方便表示这里 fillString 用了ES6 的默认参数,不影响理解
  279. String.prototype.padStart = function(maxLength, fillString = ' ') {
  280. if (Object.prototype.toString.call(fillString) !== '[object String]') {
  281. throw new TypeError(
  282. 'fillString must be String'
  283. )
  284. }
  285. const str = this
  286. // 返回 String(str) 这里是为了使返回的值是字符串字面量,在控制台中更符合直觉
  287. if (str.length >= maxLength) return String(str)
  288. const fillLength = maxLength - str.length
  289. let times = Math.ceil(fillLength / fillString.length)
  290. while (times >>= 1) {
  291. fillString += fillString
  292. if (times === 1) {
  293. fillString += fillString
  294. }
  295. }
  296. return fillString.slice(0, fillLength) + str
  297. }
  298. }
  299. /**
  300. * @description 格式化时间
  301. * @param {String|Number} dateTime 需要格式化的时间戳
  302. * @param {String} fmt 格式化规则 yyyy:mm:dd|yyyy:mm|yyyy年mm月dd日|yyyy年mm月dd日 hh时MM分等,可自定义组合 默认yyyy-mm-dd
  303. * @returns {string} 返回格式化后的字符串
  304. */
  305. export function timeFormat(dateTime = null, formatStr = 'yyyy-mm-dd') {
  306. let date
  307. // 若传入时间为假值,则取当前时间
  308. if (!dateTime) {
  309. date = new Date()
  310. }
  311. // 若为unix秒时间戳,则转为毫秒时间戳(逻辑有点奇怪,但不敢改,以保证历史兼容)
  312. else if (/^\d{10}$/.test(dateTime.toString().trim())) {
  313. date = new Date(dateTime * 1000)
  314. }
  315. // 若用户传入字符串格式时间戳,new Date无法解析,需做兼容
  316. else if (typeof dateTime === 'string' && /^\d+$/.test(dateTime.trim())) {
  317. date = new Date(Number(dateTime))
  318. }
  319. // 其他都认为符合 RFC 2822 规范
  320. else {
  321. // 处理平台性差异,在Safari/Webkit中,new Date仅支持/作为分割符的字符串时间
  322. date = new Date(
  323. typeof dateTime === 'string'
  324. ? dateTime.replace(/-/g, '/')
  325. : dateTime
  326. )
  327. }
  328. const timeSource = {
  329. 'y': date.getFullYear().toString(), // 年
  330. 'm': (date.getMonth() + 1).toString().padStart(2, '0'), // 月
  331. 'd': date.getDate().toString().padStart(2, '0'), // 日
  332. 'h': date.getHours().toString().padStart(2, '0'), // 时
  333. 'M': date.getMinutes().toString().padStart(2, '0'), // 分
  334. 's': date.getSeconds().toString().padStart(2, '0') // 秒
  335. // 有其他格式化字符需求可以继续添加,必须转化成字符串
  336. }
  337. for (const key in timeSource) {
  338. const [ret] = new RegExp(`${key}+`).exec(formatStr) || []
  339. if (ret) {
  340. // 年可能只需展示两位
  341. const beginIndex = key === 'y' && ret.length === 2 ? 2 : 0
  342. formatStr = formatStr.replace(ret, timeSource[key].slice(beginIndex))
  343. }
  344. }
  345. return formatStr
  346. }
  347. /**
  348. * @description 时间戳转为多久之前
  349. * @param {String|Number} timestamp 时间戳
  350. * @param {String|Boolean} format
  351. * 格式化规则如果为时间格式字符串超出一定时间范围返回固定的时间格式
  352. * 如果为布尔值false无论什么时间都返回多久以前的格式
  353. * @returns {string} 转化后的内容
  354. */
  355. export function timeFrom(timestamp = null, format = 'yyyy-mm-dd') {
  356. if (timestamp == null) timestamp = Number(new Date())
  357. timestamp = parseInt(timestamp)
  358. // 判断用户输入的时间戳是秒还是毫秒,一般前端js获取的时间戳是毫秒(13位),后端传过来的为秒(10位)
  359. if (timestamp.toString().length == 10) timestamp *= 1000
  360. let timer = (new Date()).getTime() - timestamp
  361. timer = parseInt(timer / 1000)
  362. // 如果小于5分钟,则返回"刚刚",其他以此类推
  363. let tips = ''
  364. switch (true) {
  365. case timer < 300:
  366. tips = '刚刚'
  367. break
  368. case timer >= 300 && timer < 3600:
  369. tips = `${parseInt(timer / 60)}分钟前`
  370. break
  371. case timer >= 3600 && timer < 86400:
  372. tips = `${parseInt(timer / 3600)}小时前`
  373. break
  374. case timer >= 86400 && timer < 2592000:
  375. tips = `${parseInt(timer / 86400)}天前`
  376. break
  377. default:
  378. // 如果format为false,则无论什么时间戳,都显示xx之前
  379. if (format === false) {
  380. if (timer >= 2592000 && timer < 365 * 86400) {
  381. tips = `${parseInt(timer / (86400 * 30))}个月前`
  382. } else {
  383. tips = `${parseInt(timer / (86400 * 365))}年前`
  384. }
  385. } else {
  386. tips = timeFormat(timestamp, format)
  387. }
  388. }
  389. return tips
  390. }
  391. /**
  392. * @description 去除空格
  393. * @param String str 需要去除空格的字符串
  394. * @param String pos both(左右)|left|right|all 默认both
  395. */
  396. export function trim(str, pos = 'both') {
  397. str = String(str)
  398. if (pos == 'both') {
  399. return str.replace(/^\s+|\s+$/g, '')
  400. }
  401. if (pos == 'left') {
  402. return str.replace(/^\s*/, '')
  403. }
  404. if (pos == 'right') {
  405. return str.replace(/(\s*$)/g, '')
  406. }
  407. if (pos == 'all') {
  408. return str.replace(/\s+/g, '')
  409. }
  410. return str
  411. }
  412. /**
  413. * @description 对象转url参数
  414. * @param {object} data,对象
  415. * @param {Boolean} isPrefix,是否自动加上"?"
  416. * @param {string} arrayFormat 规则 indices|brackets|repeat|comma
  417. */
  418. export function queryParams(data = {}, isPrefix = true, arrayFormat = 'brackets') {
  419. const prefix = isPrefix ? '?' : ''
  420. const _result = []
  421. if (['indices', 'brackets', 'repeat', 'comma'].indexOf(arrayFormat) == -1) arrayFormat = 'brackets'
  422. for (const key in data) {
  423. const value = data[key]
  424. // 去掉为空的参数
  425. if (['', undefined, null].indexOf(value) >= 0) {
  426. continue
  427. }
  428. // 如果值为数组,另行处理
  429. if (value.constructor === Array) {
  430. // e.g. {ids: [1, 2, 3]}
  431. switch (arrayFormat) {
  432. case 'indices':
  433. // 结果: ids[0]=1&ids[1]=2&ids[2]=3
  434. for (let i = 0; i < value.length; i++) {
  435. _result.push(`${key}[${i}]=${value[i]}`)
  436. }
  437. break
  438. case 'brackets':
  439. // 结果: ids[]=1&ids[]=2&ids[]=3
  440. value.forEach((_value) => {
  441. _result.push(`${key}[]=${_value}`)
  442. })
  443. break
  444. case 'repeat':
  445. // 结果: ids=1&ids=2&ids=3
  446. value.forEach((_value) => {
  447. _result.push(`${key}=${_value}`)
  448. })
  449. break
  450. case 'comma':
  451. // 结果: ids=1,2,3
  452. let commaStr = ''
  453. value.forEach((_value) => {
  454. commaStr += (commaStr ? ',' : '') + _value
  455. })
  456. _result.push(`${key}=${commaStr}`)
  457. break
  458. default:
  459. value.forEach((_value) => {
  460. _result.push(`${key}[]=${_value}`)
  461. })
  462. }
  463. } else {
  464. _result.push(`${key}=${value}`)
  465. }
  466. }
  467. return _result.length ? prefix + _result.join('&') : ''
  468. }
  469. /**
  470. * 显示消息提示框
  471. * @param {String} title 提示的内容长度与 icon 取值有关
  472. * @param {Number} duration 提示的延迟时间单位毫秒默认2000
  473. */
  474. export function toast(title, duration = 2000) {
  475. uni.showToast({
  476. title: String(title),
  477. icon: 'none',
  478. duration
  479. })
  480. }
  481. /**
  482. * @description 根据主题type值,获取对应的图标
  483. * @param {String} type 主题名称,primary|info|error|warning|success
  484. * @param {boolean} fill 是否使用fill填充实体的图标
  485. */
  486. export function type2icon(type = 'success', fill = false) {
  487. // 如果非预置值,默认为success
  488. if (['primary', 'info', 'error', 'warning', 'success'].indexOf(type) == -1) type = 'success'
  489. let iconName = ''
  490. // 目前(2019-12-12),info和primary使用同一个图标
  491. switch (type) {
  492. case 'primary':
  493. iconName = 'info-circle'
  494. break
  495. case 'info':
  496. iconName = 'info-circle'
  497. break
  498. case 'error':
  499. iconName = 'close-circle'
  500. break
  501. case 'warning':
  502. iconName = 'error-circle'
  503. break
  504. case 'success':
  505. iconName = 'checkmark-circle'
  506. break
  507. default:
  508. iconName = 'checkmark-circle'
  509. }
  510. // 是否是实体类型,加上-fill,在icon组件库中,实体的类名是后面加-fill的
  511. if (fill) iconName += '-fill'
  512. return iconName
  513. }
  514. /**
  515. * @description 数字格式化
  516. * @param {number|string} number 要格式化的数字
  517. * @param {number} decimals 保留几位小数
  518. * @param {string} decimalPoint 小数点符号
  519. * @param {string} thousandsSeparator 千分位符号
  520. * @returns {string} 格式化后的数字
  521. */
  522. export function priceFormat(number, decimals = 0, decimalPoint = '.', thousandsSeparator = ',') {
  523. number = (`${number}`).replace(/[^0-9+-Ee.]/g, '')
  524. const n = !isFinite(+number) ? 0 : +number
  525. const prec = !isFinite(+decimals) ? 0 : Math.abs(decimals)
  526. const sep = (typeof thousandsSeparator === 'undefined') ? ',' : thousandsSeparator
  527. const dec = (typeof decimalPoint === 'undefined') ? '.' : decimalPoint
  528. let s = ''
  529. s = (prec ? round(n, prec) + '' : `${Math.round(n)}`).split('.')
  530. const re = /(-?\d+)(\d{3})/
  531. while (re.test(s[0])) {
  532. s[0] = s[0].replace(re, `$1${sep}$2`)
  533. }
  534. if ((s[1] || '').length < prec) {
  535. s[1] = s[1] || ''
  536. s[1] += new Array(prec - s[1].length + 1).join('0')
  537. }
  538. return s.join(dec)
  539. }
  540. /**
  541. * @description 获取duration值
  542. * 如果带有ms或者s直接返回如果大于一定值认为是ms单位小于一定值认为是s单位
  543. * 比如以30位阈值那么300大于30可以理解为用户想要的是300ms而不是想花300s去执行一个动画
  544. * @param {String|number} value 比如: "1s"|"100ms"|1|100
  545. * @param {boolean} unit 提示: 如果是false 默认返回number
  546. * @return {string|number}
  547. */
  548. export function getDuration(value, unit = true) {
  549. const valueNum = parseInt(value)
  550. if (unit) {
  551. if (/s$/.test(value)) return value
  552. return value > 30 ? `${value}ms` : `${value}s`
  553. }
  554. if (/ms$/.test(value)) return valueNum
  555. if (/s$/.test(value)) return valueNum > 30 ? valueNum : valueNum * 1000
  556. return valueNum
  557. }
  558. /**
  559. * @description 日期的月或日补零操作
  560. * @param {String} value 需要补零的值
  561. */
  562. export function padZero(value) {
  563. return `00${value}`.slice(-2)
  564. }
  565. /**
  566. * @description 在u-form的子组件内容发生变化或者失去焦点时尝试通知u-form执行校验方法
  567. * @param {*} instance
  568. * @param {*} event
  569. */
  570. export function formValidate(instance, event) {
  571. const formItem = $parent.call(instance, 'u-form-item')
  572. const form = $parent.call(instance, 'u-form')
  573. // 如果发生变化的input或者textarea等,其父组件中有u-form-item或者u-form等,就执行form的validate方法
  574. // 同时将form-item的pros传递给form,让其进行精确对象验证
  575. if (formItem && form) {
  576. form.validateField(formItem.prop, () => {}, event)
  577. }
  578. }
  579. /**
  580. * @description 获取某个对象下的属性用于通过类似'a.b.c'的形式去获取一个对象的的属性的形式
  581. * @param {object} obj 对象
  582. * @param {string} key 需要获取的属性字段
  583. * @returns {*}
  584. */
  585. export function getProperty(obj, key) {
  586. if (typeof obj !== 'object' || null == obj) {
  587. return ''
  588. }
  589. if (typeof key !== 'string' || key === '') {
  590. return ''
  591. }
  592. if (key.indexOf('.') !== -1) {
  593. const keys = key.split('.')
  594. let firstObj = obj[keys[0]] || {}
  595. for (let i = 1; i < keys.length; i++) {
  596. if (firstObj) {
  597. firstObj = firstObj[keys[i]]
  598. }
  599. }
  600. return firstObj
  601. }
  602. return obj[key]
  603. }
  604. /**
  605. * @description 设置对象的属性值如果'a.b.c'的形式进行设置
  606. * @param {object} obj 对象
  607. * @param {string} key 需要设置的属性
  608. * @param {string} value 设置的值
  609. */
  610. export function setProperty(obj, key, value) {
  611. if (typeof obj !== 'object' || null == obj) {
  612. return
  613. }
  614. // 递归赋值
  615. const inFn = function(_obj, keys, v) {
  616. // 最后一个属性key
  617. if (keys.length === 1) {
  618. _obj[keys[0]] = v
  619. return
  620. }
  621. // 0~length-1个key
  622. while (keys.length > 1) {
  623. const k = keys[0]
  624. if (!_obj[k] || (typeof _obj[k] !== 'object')) {
  625. _obj[k] = {}
  626. }
  627. const key = keys.shift()
  628. // 自调用判断是否存在属性,不存在则自动创建对象
  629. inFn(_obj[k], keys, v)
  630. }
  631. }
  632. if (typeof key !== 'string' || key === '') {
  633. } else if (key.indexOf('.') !== -1) { // 支持多层级赋值操作
  634. const keys = key.split('.')
  635. inFn(obj, keys, value)
  636. } else {
  637. obj[key] = value
  638. }
  639. }
  640. /**
  641. * @description 获取当前页面路径
  642. */
  643. export function page() {
  644. const pages = getCurrentPages()
  645. // 某些特殊情况下(比如页面进行redirectTo时的一些时机),pages可能为空数组
  646. return `/${pages[pages.length - 1].route || ''}`
  647. }
  648. /**
  649. * @description 获取当前路由栈实例数组
  650. */
  651. export function pages() {
  652. const pages = getCurrentPages()
  653. return pages
  654. }
  655. export default {
  656. range,
  657. getPx,
  658. sleep,
  659. os,
  660. sys,
  661. random,
  662. guid,
  663. $parent,
  664. addStyle,
  665. addUnit,
  666. deepClone,
  667. deepMerge,
  668. shallowMerge,
  669. error,
  670. randomArray,
  671. timeFormat,
  672. timeFrom,
  673. trim,
  674. queryParams,
  675. toast,
  676. type2icon,
  677. priceFormat,
  678. getDuration,
  679. padZero,
  680. formValidate,
  681. getProperty,
  682. setProperty,
  683. page,
  684. pages,
  685. // setConfig
  686. }