utils.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. const screen = uni.getSystemInfoSync().windowWidth / 750;
  2. // 缓存图片
  3. let cache = {}
  4. export function isNumber(value) {
  5. return /^-?\d+(\.\d+)?$/.test(value);
  6. }
  7. export function toPx(value, baseSize) {
  8. // 如果是数字
  9. if (typeof value === 'number') {
  10. return value
  11. }
  12. // 如果是字符串数字
  13. if (isNumber(value)) {
  14. return value * 1
  15. }
  16. // 如果有单位
  17. if (typeof value === 'string') {
  18. const reg = /^-?([0-9]+)?([.]{1}[0-9]+){0,1}(em|rpx|px|%)$/g
  19. const results = reg.exec(value);
  20. if (!value || !results) {
  21. return 0;
  22. }
  23. const unit = results[3];
  24. value = parseFloat(value);
  25. let res = 0;
  26. if (unit === 'rpx') {
  27. res = Math.floor(value * (screen || 0.5) * 1);
  28. } else if (unit === 'px') {
  29. res = Math.floor(value * 1);
  30. } else if (unit === '%') {
  31. res = Math.floor(value * toPx(baseSize) / 100);
  32. } else if (unit === 'em') {
  33. res = Math.ceil(value * toPx(baseSize || 14));
  34. }
  35. return res;
  36. }
  37. }
  38. // 计算版本
  39. export function compareVersion(v1, v2) {
  40. v1 = v1.split('.')
  41. v2 = v2.split('.')
  42. const len = Math.max(v1.length, v2.length)
  43. while (v1.length < len) {
  44. v1.push('0')
  45. }
  46. while (v2.length < len) {
  47. v2.push('0')
  48. }
  49. for (let i = 0; i < len; i++) {
  50. const num1 = parseInt(v1[i], 10)
  51. const num2 = parseInt(v2[i], 10)
  52. if (num1 > num2) {
  53. return 1
  54. } else if (num1 < num2) {
  55. return -1
  56. }
  57. }
  58. return 0
  59. }
  60. /** 从 0x20 开始到 0x80 的字符宽度数据 */
  61. export const CHAR_WIDTH_SCALE_MAP = [0.296, 0.313, 0.436, 0.638, 0.586, 0.89, 0.87, 0.256, 0.334, 0.334, 0.455, 0.742,
  62. 0.241, 0.433, 0.241, 0.427, 0.586, 0.586, 0.586, 0.586, 0.586, 0.586, 0.586, 0.586, 0.586, 0.586, 0.241, 0.241, 0.742,
  63. 0.742, 0.742, 0.483, 1.031, 0.704, 0.627, 0.669, 0.762, 0.55, 0.531, 0.744, 0.773, 0.294, 0.396, 0.635, 0.513, 0.977,
  64. 0.813, 0.815, 0.612, 0.815, 0.653, 0.577, 0.573, 0.747, 0.676, 1.018, 0.645, 0.604, 0.62, 0.334, 0.416, 0.334, 0.742,
  65. 0.448, 0.295, 0.553, 0.639, 0.501, 0.64, 0.567, 0.347, 0.64, 0.616, 0.266, 0.267, 0.544, 0.266, 0.937, 0.616, 0.636,
  66. 0.639, 0.64, 0.382, 0.463, 0.373, 0.616, 0.525, 0.79, 0.507, 0.529, 0.492, 0.334, 0.269, 0.334, 0.742, 0.296
  67. ];
  68. // #ifdef MP
  69. const prefix = () => {
  70. // #ifdef MP-TOUTIAO
  71. return tt
  72. // #endif
  73. // #ifdef MP-WEIXIN
  74. return wx
  75. // #endif
  76. // #ifdef MP-BAIDU
  77. return swan
  78. // #endif
  79. // #ifdef MP-ALIPAY
  80. return my
  81. // #endif
  82. // #ifdef MP-QQ
  83. return qq
  84. // #endif
  85. // #ifdef MP-360
  86. return qh
  87. // #endif
  88. }
  89. const base64ToArrayBuffer = (data) => {
  90. /**
  91. * base64ToArrayBuffer
  92. * Base64Binary.decode(base64_string);
  93. * Base64Binary.decodeArrayBuffer(base64_string);
  94. */
  95. const Base64Binary = {
  96. _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
  97. /* will return a Uint8Array type */
  98. decodeArrayBuffer(input) {
  99. const bytes = (input.length/4) * 3;
  100. const ab = new ArrayBuffer(bytes);
  101. this.decode(input, ab);
  102. return ab;
  103. },
  104. removePaddingChars(input) {
  105. const lkey = this._keyStr.indexOf(input.charAt(input.length - 1));
  106. if(lkey == 64){
  107. return input.substring(0,input.length - 1);
  108. }
  109. return input;
  110. },
  111. decode(input, arrayBuffer) {
  112. //get last chars to see if are valid
  113. input = this.removePaddingChars(input);
  114. input = this.removePaddingChars(input);
  115. const bytes = parseInt((input.length / 4) * 3, 10);
  116. let uarray;
  117. let chr1, chr2, chr3;
  118. let enc1, enc2, enc3, enc4;
  119. let i = 0;
  120. let j = 0;
  121. if (arrayBuffer)
  122. uarray = new Uint8Array(arrayBuffer);
  123. else
  124. uarray = new Uint8Array(bytes);
  125. input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
  126. for (i=0; i<bytes; i+=3) {
  127. //get the 3 octects in 4 ascii chars
  128. enc1 = this._keyStr.indexOf(input.charAt(j++));
  129. enc2 = this._keyStr.indexOf(input.charAt(j++));
  130. enc3 = this._keyStr.indexOf(input.charAt(j++));
  131. enc4 = this._keyStr.indexOf(input.charAt(j++));
  132. chr1 = (enc1 << 2) | (enc2 >> 4);
  133. chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
  134. chr3 = ((enc3 & 3) << 6) | enc4;
  135. uarray[i] = chr1;
  136. if (enc3 != 64) uarray[i+1] = chr2;
  137. if (enc4 != 64) uarray[i+2] = chr3;
  138. }
  139. return uarray;
  140. }
  141. }
  142. return (uni.base64ToArrayBuffer && uni.base64ToArrayBuffer(data)) || Base64Binary.decodeArrayBuffer(data)
  143. }
  144. // #endif
  145. /**
  146. * base64转路径
  147. * @param {Object} base64
  148. */
  149. export function base64ToPath(base64) {
  150. const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64) || [];
  151. return new Promise((resolve, reject) => {
  152. // #ifdef MP
  153. const fs = uni.getFileSystemManager()
  154. //自定义文件名
  155. if (!format) {
  156. console.error('ERROR_BASE64SRC_PARSE')
  157. reject(new Error('ERROR_BASE64SRC_PARSE'))
  158. }
  159. const time = new Date().getTime();
  160. let pre = prefix()
  161. const filePath = `${pre.env.USER_DATA_PATH}/${time}.${format}`
  162. let buffer = base64ToArrayBuffer(bodyData)
  163. fs.writeFile({
  164. filePath,
  165. data: buffer,
  166. encoding: 'binary',
  167. success() {
  168. resolve(filePath)
  169. },
  170. fail(err) {
  171. console.error('获取base64图片失败', JSON.stringify(err))
  172. reject(err)
  173. }
  174. })
  175. // #endif
  176. // #ifdef H5
  177. // mime类型
  178. let mimeString = base64.split(',')[0].split(':')[1].split(';')[0];
  179. //base64 解码
  180. let byteString = atob(base64.split(',')[1]);
  181. //创建缓冲数组
  182. let arrayBuffer = new ArrayBuffer(byteString.length);
  183. //创建视图
  184. let intArray = new Uint8Array(arrayBuffer);
  185. for (let i = 0; i < byteString.length; i++) {
  186. intArray[i] = byteString.charCodeAt(i);
  187. }
  188. resolve(URL.createObjectURL(new Blob([intArray], { type: mimeString })))
  189. // #endif
  190. // #ifdef APP-PLUS
  191. const bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
  192. bitmap.loadBase64Data(base64, () => {
  193. if (!format) {
  194. console.error('ERROR_BASE64SRC_PARSE')
  195. reject(new Error('ERROR_BASE64SRC_PARSE'))
  196. }
  197. const time = new Date().getTime();
  198. const filePath = `_doc/uniapp_temp/${time}.${format}`
  199. bitmap.save(filePath, {},
  200. () => {
  201. bitmap.clear()
  202. resolve(filePath)
  203. },
  204. (error) => {
  205. bitmap.clear()
  206. console.error(`${JSON.stringify(error)}`)
  207. reject(error)
  208. })
  209. }, (error) => {
  210. bitmap.clear()
  211. console.error(`${JSON.stringify(error)}`)
  212. reject(error)
  213. })
  214. // #endif
  215. })
  216. }
  217. /**
  218. * 路径转base64
  219. * @param {Object} string
  220. */
  221. export function pathToBase64(path) {
  222. return new Promise((resolve, reject) => {
  223. // #ifdef H5
  224. const _canvas = ()=> {
  225. let image = new Image();
  226. image.onload = function() {
  227. let canvas = document.createElement('canvas');
  228. // 获取图片原始宽高
  229. canvas.width = this.naturalWidth;
  230. canvas.height = this.naturalHeight;
  231. // 将图片插入画布并开始绘制
  232. canvas.getContext('2d').drawImage(image, 0, 0);
  233. let result = canvas.toDataURL('image/png')
  234. resolve(result);
  235. canvas.height = canvas.width = 0
  236. }
  237. image.src = path
  238. image.setAttribute("crossOrigin",'Anonymous');
  239. image.src = path;
  240. image.onerror = (error) => {
  241. console.error(`urlToBase64 error: ${path}`, JSON.stringify(error))
  242. reject(new Error('urlToBase64 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. console.error('blobToBase64 error:', JSON.stringify(error))
  253. reject(new Error('blobToBase64 error'));
  254. };
  255. }
  256. const isFileReader = typeof FileReader === 'function'
  257. if(/^(http|\/\/)/.test(path) && isFileReader ) {
  258. window.URL = window.URL || window.webkitURL;
  259. const xhr = new XMLHttpRequest();
  260. xhr.open("get", path, true);
  261. xhr.timeout = 2000;
  262. xhr.responseType = "blob";
  263. xhr.onload = function() {
  264. if(this.status == 200) {
  265. _fileReader(this.response)
  266. } else {
  267. _canvas()
  268. }
  269. }
  270. xhr.onreadystatechange = function() {
  271. if(this.status === 0) {
  272. console.error('图片跨域了,得后端处理咯')
  273. }
  274. }
  275. xhr.send();
  276. } else if(/^blob/.test(path) && isFileReader){
  277. _fileReader(path)
  278. } else {
  279. _canvas()
  280. }
  281. // #endif
  282. // #ifdef MP
  283. if(uni.canIUse('getFileSystemManager')) {
  284. uni.getFileSystemManager().readFile({
  285. filePath: path,
  286. encoding: 'base64',
  287. success: (res) => {
  288. resolve('data:image/png;base64,' + res.data)
  289. },
  290. fail: (error) => {
  291. console.error('urlToBase64 error:', JSON.stringify(error))
  292. reject(error)
  293. }
  294. })
  295. }
  296. // #endif
  297. // #ifdef APP-PLUS
  298. plus.io.resolveLocalFileSystemURL(getLocalFilePath(path), (entry) => {
  299. entry.file((file) => {
  300. const fileReader = new plus.io.FileReader()
  301. fileReader.onload = (data) => {
  302. resolve(data.target.result)
  303. }
  304. fileReader.onerror = (error) => {
  305. console.error('pathToBase64 error:', JSON.stringify(error))
  306. reject(error)
  307. }
  308. fileReader.readAsDataURL(file)
  309. }, (error) => {
  310. console.error('pathToBase64 error:', JSON.stringify(error))
  311. reject(error)
  312. })
  313. }, (error) => {
  314. console.error('pathToBase64 error:', JSON.stringify(error))
  315. reject(error)
  316. })
  317. // #endif
  318. })
  319. }
  320. // #ifdef APP-PLUS
  321. const getLocalFilePath = (path)=> {
  322. if (path.indexOf('_www') === 0 || path.indexOf('_doc') === 0 || path.indexOf('_documents') === 0 || path.indexOf('_downloads') === 0) {
  323. return path
  324. }
  325. if (path.indexOf('file://') === 0) {
  326. return path
  327. }
  328. if (path.indexOf('/storage/emulated/0/') === 0) {
  329. return path
  330. }
  331. if (path.indexOf('/') === 0) {
  332. const localFilePath = plus.io.convertAbsoluteFileSystem(path)
  333. if (localFilePath !== path) {
  334. return localFilePath
  335. } else {
  336. path = path.substr(1)
  337. }
  338. }
  339. return '_www/' + path
  340. }
  341. // #endif
  342. export function getImageInfo(img, isH5PathToBase64) {
  343. return new Promise(async (resolve, reject) => {
  344. const base64Reg = /^data:image\/(\w+);base64/
  345. const localReg = /^\.|^\/(?=[^\/])/;
  346. const networkReg = /^(http|\/\/)/
  347. // #ifdef H5
  348. if(networkReg.test(img) && isH5PathToBase64) {
  349. img = await pathToBase64(img)
  350. }
  351. // #endif
  352. // #ifndef MP-ALIPAY
  353. if(base64Reg.test(img)) {
  354. if(!cache[img]) {
  355. const imgName = img
  356. img = await base64ToPath(img)
  357. cache[imgName] = img
  358. } else {
  359. img = cache[img]
  360. }
  361. }
  362. // #endif
  363. if(cache[img] && cache[img].errMsg) {
  364. resolve(cache[img])
  365. } else {
  366. uni.getImageInfo({
  367. src: img,
  368. success: (image) => {
  369. // #ifdef MP-WEIXIN || MP-BAIDU || MP-QQ || MP-TOUTIAO
  370. image.path = localReg.test(img) ? `/${image.path}` : image.path;
  371. // #endif
  372. // image.path = /^(http|\/\/|\/|wxfile|data:image\/(\w+);base64|file|bdfile|ttfile|blob)/.test(image.path) ? image.path : `/${image.path}`;
  373. image.url = img
  374. cache[img] = image
  375. resolve(cache[img])
  376. },
  377. fail(err) {
  378. resolve({path: img})
  379. console.error(`getImageInfo:fail ${img} failed ${JSON.stringify(err)}`);
  380. }
  381. })
  382. }
  383. })
  384. }
  385. export class DataUtil {
  386. /**
  387. * 设置差异数据
  388. * @param component
  389. * @param data
  390. */
  391. setDiffData(component, data) {
  392. const diffData = {};
  393. // 遍历获取到有差异的数据
  394. Object.keys(data).forEach(key => {
  395. if (component[key] !== data[key]) {
  396. diffData[key] = data[key];
  397. }
  398. });
  399. // 设置数据
  400. if (Object.keys(diffData).length) {
  401. // component.setData(diffData);
  402. }
  403. }
  404. }
  405. // const dataUtil = new DataUtil;
  406. // export dataUtil;