utils.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. const networkReg = /^(http|\/\/)/;
  2. export const isBase64 = (path) => /^data:image\/(\w+);base64/.test(path);
  3. export function sleep(delay) {
  4. return new Promise(resolve => setTimeout(resolve, delay))
  5. }
  6. const isDev = ['devtools'].includes(uni.getSystemInfoSync().platform)
  7. // 缓存图片
  8. let cache = {}
  9. export function isNumber(value) {
  10. return /^-?\d+(\.\d+)?$/.test(value);
  11. }
  12. export function toPx(value, baseSize, isDecimal = false) {
  13. // 如果是数字
  14. if (typeof value === 'number') {
  15. return value
  16. }
  17. // 如果是字符串数字
  18. if (isNumber(value)) {
  19. return value * 1
  20. }
  21. // 如果有单位
  22. if (typeof value === 'string') {
  23. const reg = /^-?([0-9]+)?([.]{1}[0-9]+){0,1}(em|rpx|px|%)$/g
  24. const results = reg.exec(value);
  25. if (!value || !results) {
  26. return 0;
  27. }
  28. const unit = results[3];
  29. value = parseFloat(value);
  30. let res = 0;
  31. if (unit === 'rpx') {
  32. res = uni.upx2px(value);
  33. } else if (unit === 'px') {
  34. res = value * 1;
  35. } else if (unit === '%') {
  36. res = value * toPx(baseSize) / 100;
  37. } else if (unit === 'em') {
  38. res = value * toPx(baseSize || 14);
  39. }
  40. return isDecimal ? res.toFixed(2) * 1 : Math.round(res);
  41. }
  42. return 0
  43. }
  44. // 计算版本
  45. export function compareVersion(v1, v2) {
  46. v1 = v1.split('.')
  47. v2 = v2.split('.')
  48. const len = Math.max(v1.length, v2.length)
  49. while (v1.length < len) {
  50. v1.push('0')
  51. }
  52. while (v2.length < len) {
  53. v2.push('0')
  54. }
  55. for (let i = 0; i < len; i++) {
  56. const num1 = parseInt(v1[i], 10)
  57. const num2 = parseInt(v2[i], 10)
  58. if (num1 > num2) {
  59. return 1
  60. } else if (num1 < num2) {
  61. return -1
  62. }
  63. }
  64. return 0
  65. }
  66. // #ifdef MP
  67. export const prefix = () => {
  68. // #ifdef MP-TOUTIAO
  69. return tt
  70. // #endif
  71. // #ifdef MP-WEIXIN
  72. return wx
  73. // #endif
  74. // #ifdef MP-BAIDU
  75. return swan
  76. // #endif
  77. // #ifdef MP-ALIPAY
  78. return my
  79. // #endif
  80. // #ifdef MP-QQ
  81. return qq
  82. // #endif
  83. // #ifdef MP-360
  84. return qh
  85. // #endif
  86. }
  87. // #endif
  88. const base64ToArrayBuffer = (data) => {
  89. // #ifndef MP-WEIXIN || APP-PLUS
  90. /**
  91. * Base64Binary.decode(base64_string);
  92. * Base64Binary.decodeArrayBuffer(base64_string);
  93. */
  94. const Base64Binary = {
  95. _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
  96. /* will return a Uint8Array type */
  97. decodeArrayBuffer(input) {
  98. const bytes = (input.length / 4) * 3;
  99. const ab = new ArrayBuffer(bytes);
  100. this.decode(input, ab);
  101. return ab;
  102. },
  103. removePaddingChars(input) {
  104. const lkey = this._keyStr.indexOf(input.charAt(input.length - 1));
  105. if (lkey == 64) {
  106. return input.substring(0, input.length - 1);
  107. }
  108. return input;
  109. },
  110. decode(input, arrayBuffer) {
  111. //get last chars to see if are valid
  112. input = this.removePaddingChars(input);
  113. input = this.removePaddingChars(input);
  114. const bytes = parseInt((input.length / 4) * 3, 10);
  115. let uarray;
  116. let chr1, chr2, chr3;
  117. let enc1, enc2, enc3, enc4;
  118. let i = 0;
  119. let j = 0;
  120. if (arrayBuffer)
  121. uarray = new Uint8Array(arrayBuffer);
  122. else
  123. uarray = new Uint8Array(bytes);
  124. input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
  125. for (i = 0; i < bytes; i += 3) {
  126. //get the 3 octects in 4 ascii chars
  127. enc1 = this._keyStr.indexOf(input.charAt(j++));
  128. enc2 = this._keyStr.indexOf(input.charAt(j++));
  129. enc3 = this._keyStr.indexOf(input.charAt(j++));
  130. enc4 = this._keyStr.indexOf(input.charAt(j++));
  131. chr1 = (enc1 << 2) | (enc2 >> 4);
  132. chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
  133. chr3 = ((enc3 & 3) << 6) | enc4;
  134. uarray[i] = chr1;
  135. if (enc3 != 64) uarray[i + 1] = chr2;
  136. if (enc4 != 64) uarray[i + 2] = chr3;
  137. }
  138. return uarray;
  139. }
  140. }
  141. return Base64Binary.decodeArrayBuffer(data)
  142. // #endif
  143. // #ifdef MP-WEIXIN || APP-PLUS
  144. return uni.base64ToArrayBuffer(data)
  145. // #endif
  146. }
  147. /**
  148. * base64转路径
  149. * @param {Object} base64
  150. */
  151. export function base64ToPath(base64) {
  152. const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64) || [];
  153. return new Promise((resolve, reject) => {
  154. // #ifdef MP
  155. const fs = uni.getFileSystemManager()
  156. //自定义文件名
  157. if (!format) {
  158. reject(new Error('ERROR_BASE64SRC_PARSE'))
  159. }
  160. const time = new Date().getTime();
  161. let pre = prefix()
  162. const filePath = `${pre.env.USER_DATA_PATH}/${time}.${format}`
  163. //let buffer = base64ToArrayBuffer(bodyData)
  164. fs.writeFile({
  165. filePath,
  166. data: base64.replace(/^data:\S+\/\S+;base64,/, ''),
  167. encoding: 'base64',
  168. // data: buffer,
  169. // encoding: 'binary',
  170. success() {
  171. resolve(filePath)
  172. },
  173. fail(err) {
  174. reject(err)
  175. }
  176. })
  177. // #endif
  178. // #ifdef H5
  179. // mime类型
  180. let mimeString = base64.split(',')[0].split(':')[1].split(';')[0];
  181. //base64 解码
  182. let byteString = atob(base64.split(',')[1]);
  183. //创建缓冲数组
  184. let arrayBuffer = new ArrayBuffer(byteString.length);
  185. //创建视图
  186. let intArray = new Uint8Array(arrayBuffer);
  187. for (let i = 0; i < byteString.length; i++) {
  188. intArray[i] = byteString.charCodeAt(i);
  189. }
  190. resolve(URL.createObjectURL(new Blob([intArray], {
  191. type: mimeString
  192. })))
  193. // #endif
  194. // #ifdef APP-PLUS
  195. const bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
  196. bitmap.loadBase64Data(base64, () => {
  197. if (!format) {
  198. reject(new Error('ERROR_BASE64SRC_PARSE'))
  199. }
  200. const time = new Date().getTime();
  201. const filePath = `_doc/uniapp_temp/${time}.${format}`
  202. bitmap.save(filePath, {},
  203. () => {
  204. bitmap.clear()
  205. resolve(filePath)
  206. },
  207. (error) => {
  208. bitmap.clear()
  209. reject(error)
  210. })
  211. }, (error) => {
  212. bitmap.clear()
  213. reject(error)
  214. })
  215. // #endif
  216. })
  217. }
  218. /**
  219. * 路径转base64
  220. * @param {Object} string
  221. */
  222. export function pathToBase64(path) {
  223. if (/^data:/.test(path)) return path
  224. return new Promise((resolve, reject) => {
  225. // #ifdef H5
  226. const _canvas = () => {
  227. let image = new Image();
  228. image.setAttribute("crossOrigin", 'Anonymous');
  229. image.onload = function() {
  230. let canvas = document.createElement('canvas');
  231. // 获取图片原始宽高
  232. canvas.width = this.naturalWidth;
  233. canvas.height = this.naturalHeight;
  234. // 将图片插入画布并开始绘制
  235. canvas.getContext('2d').drawImage(image, 0, 0);
  236. let result = canvas.toDataURL('image/png')
  237. resolve(result);
  238. canvas.height = canvas.width = 0
  239. }
  240. image.src = path
  241. image.onerror = (error) => {
  242. reject(error);
  243. };
  244. }
  245. const _fileReader = (blob) => {
  246. const fileReader = new FileReader();
  247. fileReader.onload = (e) => {
  248. resolve(e.target.result);
  249. };
  250. fileReader.readAsDataURL(blob);
  251. fileReader.onerror = (error) => {
  252. reject(error);
  253. };
  254. }
  255. const isFileReader = typeof FileReader === 'function'
  256. if (networkReg.test(path) && isFileReader) {
  257. window.URL = window.URL || window.webkitURL;
  258. const xhr = new XMLHttpRequest();
  259. xhr.open("get", path, true);
  260. xhr.timeout = 2000;
  261. xhr.responseType = "blob";
  262. xhr.onload = function() {
  263. if (this.status == 200) {
  264. _fileReader(this.response)
  265. } else {
  266. _canvas()
  267. }
  268. }
  269. xhr.onreadystatechange = function() {
  270. if (this.status === 0) {
  271. reject(new Error('图片跨域'))
  272. }
  273. }
  274. xhr.send();
  275. } else if (/^blob/.test(path) && isFileReader) {
  276. _fileReader(path)
  277. } else {
  278. _canvas()
  279. }
  280. // #endif
  281. // #ifdef MP
  282. if (uni.canIUse('getFileSystemManager')) {
  283. uni.getFileSystemManager().readFile({
  284. filePath: path,
  285. encoding: 'base64',
  286. success: (res) => {
  287. resolve('data:image/png;base64,' + res.data)
  288. },
  289. fail: (error) => {
  290. reject(error)
  291. }
  292. })
  293. }
  294. // #endif
  295. // #ifdef APP-PLUS
  296. plus.io.resolveLocalFileSystemURL(getLocalFilePath(path), (entry) => {
  297. entry.file((file) => {
  298. const fileReader = new plus.io.FileReader()
  299. fileReader.onload = (data) => {
  300. resolve(data.target.result)
  301. }
  302. fileReader.onerror = (error) => {
  303. reject(error)
  304. }
  305. fileReader.readAsDataURL(file)
  306. }, reject)
  307. }, reject)
  308. // #endif
  309. })
  310. }
  311. export function getImageInfo(img) {
  312. return new Promise(async (resolve, reject) => {
  313. if (cache[img] && cache[img].errMsg) {
  314. resolve(cache[img])
  315. } else {
  316. uni.getImageInfo({
  317. src: img,
  318. success: (image) => {
  319. if (isDev) {
  320. resolve(image)
  321. } else {
  322. cache[img] = image
  323. resolve(cache[img])
  324. }
  325. },
  326. fail(err) {
  327. reject({err, path: img})
  328. }
  329. })
  330. }
  331. })
  332. }
  333. export function downloadFile(url) {
  334. if (!url) return Promise.reject({
  335. err: 'no url'
  336. })
  337. return new Promise((resolve, reject) => {
  338. if(cache[url]) {
  339. return reject()
  340. }
  341. cache[url] = 1
  342. uni.downloadFile({
  343. url,
  344. success(res) {
  345. resolve(res)
  346. },
  347. fail(err) {
  348. reject(err)
  349. }
  350. })
  351. })
  352. }
  353. // #ifdef APP-PLUS
  354. const getLocalFilePath = (path) => {
  355. if (path.indexOf('_www') === 0 || path.indexOf('_doc') === 0 || path.indexOf('_documents') === 0 || path
  356. .indexOf('_downloads') === 0) {
  357. return path
  358. }
  359. if (path.indexOf('file://') === 0) {
  360. return path
  361. }
  362. if (path.indexOf('/storage/emulated/0/') === 0) {
  363. return path
  364. }
  365. if (path.indexOf('/') === 0) {
  366. const localFilePath = plus.io.convertAbsoluteFileSystem(path)
  367. if (localFilePath !== path) {
  368. return localFilePath
  369. } else {
  370. path = path.substr(1)
  371. }
  372. }
  373. return '_www/' + path
  374. }
  375. const getFile = (url) => {
  376. return new Promise((resolve, rejcet) => {
  377. plus.io.resolveLocalFileSystemURL(url, resolve, (err) => {
  378. resolve(false)
  379. })
  380. })
  381. }
  382. const createFile = ({
  383. fs,
  384. url,
  385. target,
  386. name
  387. }) => {
  388. return new Promise((resolve, reject) => {
  389. plus.io.resolveLocalFileSystemURL(url, res1 => {
  390. fs.root.getDirectory(target, {
  391. create: true
  392. }, fileEntry => {
  393. const success = () => {
  394. res1.remove()
  395. resolve()
  396. }
  397. getFile(target+name).then(res => {
  398. if(res) {
  399. res.remove((res2) => {
  400. res1.moveTo(fileEntry, name, success, reject)
  401. })
  402. }
  403. res1.moveTo(fileEntry, name, success, reject)
  404. })
  405. })
  406. }, reject)
  407. })
  408. }
  409. export function useNvue(target, version, timeout) {
  410. return new Promise((resolve, reject) => {
  411. plus.io.requestFileSystem(plus.io.PRIVATE_DOC, async (fs) => {
  412. try {
  413. cache['lime-painter'] = 0
  414. let names = ['uni.webview.1.5.3.js', 'painter.js', 'index.html']
  415. let urls = ['https://gitee.com/dcloud/uni-app/raw/dev/dist/',
  416. 'https://static-6d65bd90-8508-4d6c-abbc-a4ef5c8e49e7.bspapp.com/lime-painter/'
  417. ]
  418. const oldVersion = plus.storage.getItem('lime-painter')
  419. const isFile = await getFile(`${target}${names[1]}`)
  420. if(isFile && oldVersion && compareVersion(oldVersion, version) >= 0) {
  421. resolve()
  422. } else {
  423. for (var i = 0; i < names.length; i++) {
  424. const name = names[i]
  425. const file = await downloadFile(urls[i >= 1 ? 1 : 0] + name)
  426. await createFile({
  427. fs,
  428. url: file.tempFilePath,
  429. target,
  430. name: name.includes('uni.webview') ? 'uni.webview.js': name
  431. })
  432. }
  433. plus.storage.setItem('lime-painter', version)
  434. cache['lime-painter'] = version
  435. resolve()
  436. }
  437. } catch (e) {
  438. let index = parseInt(timeout / 20)
  439. while (!cache['lime-painter'] && index) {
  440. await sleep(20)
  441. index--
  442. }
  443. if (cache['lime-painter']) {
  444. resolve()
  445. } else {
  446. reject(e)
  447. }
  448. }
  449. }, reject)
  450. })
  451. }
  452. // #endif