img-downloader.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. 'use strict';
  2. /**
  3. * 下载图片的模块
  4. * @version 1.1.0
  5. * @author xfl <541151284@qq.com>
  6. */
  7. class Downloader{
  8. Downloader = Downloader;
  9. /**
  10. * 开始下载图片
  11. * @public
  12. * @param {String} url 图片的url
  13. * @param {String} [name] 下载后图片的名字
  14. * @returns {Promise} [err, res]
  15. * @example
  16. *
  17. let promise = downloader.load(url, imgName);
  18. promise.then(([err, res])=>{
  19. console.log(err, res); // err 和 res 只会有一个存在,另一个为null
  20. });
  21. */
  22. async load(url, name){
  23. url = url.trim();
  24. name = this.getName(url, name); //重新计算存储的文件名及扩展名
  25. let err, res;
  26. if( !this.isRemoteUrl(url) ){
  27. // #ifdef APP-PLUS || MP
  28. [err, res] = [null, {tempFilePath: url}];
  29. // #endif
  30. }else{
  31. //在web端时,downloadFile的作用只是 确定当前的资源和网络,可能会拿到一些下载失败的信息
  32. [err, res] = await uni.downloadFile({url: url});
  33. if(err){ //h5下载图片的跨域在这一步就能知道
  34. return [err, null];
  35. }else if(res.statusCode !== 200){ //可能是404
  36. res.errMsg = "downloadFile:fail";
  37. return [res, null];
  38. }
  39. }
  40. // #ifdef H5
  41. try{
  42. //如果这里传入 url,则会在另一个窗口打开图片,而不是下载
  43. this.webDownloadImg(res.tempFilePath, name);
  44. }catch(e){
  45. e.errMsg = e.errMsg || e.message || '';
  46. return [e, null];
  47. }
  48. // #endif
  49. // #ifdef MP-ALIPAY
  50. return [{errMsg: 'plat not support download!'}, null]; //在支付宝小程序中,不支持saveImageToPhotosAlbum,需要使用其它的方式实现下载
  51. // #endif
  52. // #ifdef APP-PLUS || MP
  53. [err, res] = await uni.saveImageToPhotosAlbum({filePath: res.tempFilePath});
  54. if( err ){
  55. return [err, null];
  56. }
  57. // #endif
  58. return [null, res];
  59. }
  60. /**
  61. * 计算文件名及扩展名
  62. * @public
  63. * @param {String} url 一个url, 当没有传入文件名时,可以尝试从这个url中去获取文件名
  64. * @param {String} [name] 文件名 或 文件名.扩展名
  65. * @param {String} [ext] 扩展名
  66. * @returns {String} 文件名.扩展名
  67. * @example
  68. *
  69. * 1. getName('aaa/bbbb.txt');
  70. * //=> bbbb.txt
  71. *
  72. * 2. getName('aaa/bbbb.txt', 'uuuuu');
  73. * //=> uuuuu.txt
  74. *
  75. * 3. getName('aaa/bbbb.txt', 'uuuuu', '.js');
  76. * //=> uuuuu.js
  77. *
  78. * 4. getName('aaa/bbbb.txt', 'uuuuu.kkk', '.js');
  79. * //=> uuuuu.js
  80. *
  81. * 5. getName('aaa/bbbb.txt', 'uuuuu.kkk');
  82. * //=> uuuuu.kkk
  83. */
  84. getName(url, name, ext){
  85. let arr = url.match(/(([\w\d_\-]+)(\.[\w\d_]+))$/); //默认取地址中的文件名
  86. //取出 url 中的文件名和扩展名
  87. let defaultName = '__default', defaultExt = '.png';
  88. if(arr){
  89. defaultName = arr[1] || defaultName;
  90. defaultExt = arr[3] || defaultExt;
  91. }
  92. //取出传入的 name 中的文件名和扩展名
  93. arr = name.match(/\.[\w\d_]+$/);
  94. if(arr){
  95. ext = ext || arr[0];
  96. name = name.replace(/\.[\w\d_]+$/, ''); //去掉name中的扩展名
  97. }
  98. ext = ext || defaultExt;
  99. name = name || defaultName;
  100. return name + ext;
  101. }
  102. /**
  103. * 是否是远程地址
  104. * @public
  105. * @param {String} url 需要判断的url
  106. * @returns {Boolean}
  107. */
  108. isRemoteUrl(url){
  109. return !!url.match(/^https?:\/\//i);
  110. }
  111. /**
  112. * 在web端通过a标签来下载文件
  113. * 注意,在浏览器中用户可能设置了阻止下载文件,此时代码也会正常执行完成,但其实是没有真正地下载文件的。
  114. * 如果不存在这样的资源,则默认会下载本网页(html文件)
  115. * @public
  116. * @param {String} url 要下载的图片地址
  117. * @param {String} [name=''] 下载后图片的名字
  118. */
  119. webDownloadImg(url, name = ''){ //网页中的图片下载
  120. const body = document.getElementsByTagName('body')[0];
  121. const aEle = document.createElement('a');
  122. aEle.setAttribute('download', name);
  123. aEle.style.display = 'none';
  124. aEle.href = url;
  125. aEle.target = '_blank';
  126. body.appendChild(aEle);
  127. aEle.dispatchEvent( new MouseEvent('click') ); // 模拟鼠标click点击事件
  128. document.body.removeChild(aEle);
  129. }
  130. /**
  131. * 以单例模式 获取实例对象
  132. * @static
  133. * @public
  134. */
  135. static getInstance(){
  136. if(!this.__hasInstance){
  137. this.__hasInstance = new this();
  138. }
  139. return this.__hasInstance;
  140. }
  141. }
  142. export default Downloader.getInstance();