lsj-upload.vue 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. <template>
  2. <view class="lsj-file" :style="[getStyles]">
  3. <view ref="lsj" class="hFile" :style="[getStyles]" @click="onClick">
  4. <slot><view class="defview" :style="[getStyles]">附件上传</view></slot>
  5. </view>
  6. </view>
  7. </template>
  8. <script>
  9. // 查看文档:https://ext.dcloud.net.cn/plugin?id=5459
  10. import {LsjFile} from './LsjFile.js'
  11. export default {
  12. name: 'Lsj-upload',
  13. props: {
  14. // 打印日志
  15. debug: {type: Boolean,default: false},
  16. // 自动上传
  17. instantly: {type: Boolean,default: false},
  18. // 上传接口参数设置
  19. option: {type: Object,default: ()=>{}},
  20. // 文件大小上限
  21. size: { type: Number, default: 10 },
  22. // 文件选择个数上限,超出后不触发点击
  23. count: { type: Number, default: 9 },
  24. // 是否允许多选文件
  25. multiple: {type:Boolean, default: true},
  26. // 允许上传的文件格式(多个以逗号隔开)
  27. formats: { type: String, default:''},
  28. // input file选择限制
  29. accept: {type: String,default: ''},
  30. // 微信选择文件类型
  31. //all=从所有文件选择,
  32. //video=只能选择视频文件,
  33. //image=只能选择图片文件,
  34. //file=可以选择除了图片和视频之外的其它的文件
  35. wxFileType: { type: String, default: 'all' },
  36. // webviewID需唯一,不同窗口也不要同Id
  37. childId: { type: String, default: 'lsjUpload' },
  38. // 文件选择触发面宽度
  39. width: { type: String, default: '100%' },
  40. // 文件选择触发面高度
  41. height: { type: String, default: '80rpx' },
  42. // top,left,bottom,right仅position=absolute时才需要传入
  43. top: { type: [String, Number], default: '' },
  44. left: { type: [String, Number], default: '' },
  45. bottom: { type: [String, Number], default: '' },
  46. right: { type: [String, Number], default: '' },
  47. // nvue不支持跟随窗口滚动
  48. position: {
  49. type: String,
  50. // #ifdef APP-NVUE
  51. default: 'absolute',
  52. // #endif
  53. // #ifndef APP-NVUE
  54. default: 'static',
  55. // #endif
  56. },
  57. },
  58. data() {
  59. return {
  60. }
  61. },
  62. watch: {
  63. option(v) {
  64. // #ifdef APP-PLUS
  65. this.lsjFile&&this.show();
  66. // #endif
  67. }
  68. },
  69. updated() {
  70. // #ifdef APP-PLUS
  71. if (this.isShow) {
  72. this.lsjFile&&this.show();
  73. }
  74. // #endif
  75. },
  76. computed: {
  77. getStyles() {
  78. let styles = {
  79. width: this.width,
  80. height: this.height
  81. }
  82. if (this.position == 'absolute') {
  83. styles['top'] = this.top
  84. styles['bottom'] = this.bottom
  85. styles['left'] = this.left
  86. styles['right'] = this.right
  87. styles['position'] = 'fixed'
  88. }
  89. return styles
  90. }
  91. },
  92. mounted() {
  93. this._size = 0;
  94. let WEBID = this.childId + new Date().getTime();
  95. this.lsjFile = new LsjFile({
  96. id: WEBID,
  97. debug: this.debug,
  98. width: this.width,
  99. height: this.height,
  100. option: this.option,
  101. instantly: this.instantly,
  102. // 限制条件
  103. prohibited: {
  104. // 大小
  105. size: this.size,
  106. // 允许上传的格式
  107. formats: this.formats,
  108. // 限制选择的格式
  109. accept: this.accept,
  110. count: this.count,
  111. // 是否多选
  112. multiple: this.multiple,
  113. },
  114. onchange: this.onchange,
  115. onprogress: this.onprogress,
  116. });
  117. this.create();
  118. // 需判断是否当前页显示
  119. uni.$on('lsjShow',this.show);
  120. },
  121. beforeDestroy() {
  122. uni.$off('lsjShow',this.show);
  123. // #ifdef APP-PLUS
  124. this.lsjFile.dom.close();
  125. // #endif
  126. },
  127. methods: {
  128. setFiles(array) {
  129. if (array instanceof Map) {
  130. for (let [key, item] of array) {
  131. item['progress'] = 100;
  132. item['type'] = 'success';
  133. this.lsjFile.files.set(key,item);
  134. }
  135. }
  136. else if (Array.isArray(array)) {
  137. array.forEach(item=>{
  138. if (item.name) {
  139. item['progress'] = 100;
  140. item['type'] = 'success';
  141. this.lsjFile.files.set(item.name,item);
  142. }
  143. });
  144. }
  145. this.onchange(this.lsjFile.files);
  146. },
  147. setData() {
  148. this.lsjFile&&this.lsjFile.setData(...arguments);
  149. },
  150. getDomStyles(callback) {
  151. // #ifndef APP-NVUE
  152. let view = uni
  153. .createSelectorQuery()
  154. .in(this)
  155. .select('.lsj-file')
  156. view.fields(
  157. {
  158. size: true,
  159. rect: true
  160. },
  161. ({ height, width, top, left, right, bottom }) => {
  162. uni.createSelectorQuery()
  163. .selectViewport()
  164. .scrollOffset(({ scrollTop }) => {
  165. return callback({
  166. top: parseInt(top) + parseInt(scrollTop) + 'px',
  167. left: parseInt(left) + 'px',
  168. width: parseInt(width) + 'px',
  169. height: parseInt(height) + 'px'
  170. })
  171. })
  172. .exec()
  173. }
  174. ).exec()
  175. // #endif
  176. // #ifdef APP-NVUE
  177. const dom = weex.requireModule('dom')
  178. dom.getComponentRect(this.$refs.lsj, ({ size: { height, width, top, left, right, bottom } }) => {
  179. return callback({
  180. top: parseInt(top) + 'px',
  181. left: parseInt(left) + 'px',
  182. width: parseInt(width) + 'px',
  183. height: parseInt(height) + 'px',
  184. right: parseInt(right) + 'px',
  185. bottom: parseInt(bottom) + 'px'
  186. })
  187. })
  188. // #endif
  189. },
  190. show() {
  191. if (this._size && (this._size >= this.count)) {
  192. return;
  193. }
  194. this.isShow = true;
  195. // #ifdef APP-PLUS
  196. this.lsjFile&&this.getDomStyles(styles => {
  197. this.lsjFile.dom.setStyle(styles)
  198. });
  199. // #endif
  200. // #ifdef H5
  201. this.lsjFile.dom.style.display = 'inline'
  202. // #endif
  203. },
  204. hide() {
  205. this.isShow = false;
  206. // #ifdef APP-PLUS
  207. this.lsjFile&&this.lsjFile.dom.setStyle({
  208. top: '-100px',
  209. left:'0px',
  210. width: '1px',
  211. height: '100px',
  212. });
  213. // #endif
  214. // #ifdef H5
  215. this.lsjFile.dom.style.display = 'none'
  216. // #endif
  217. },
  218. /**
  219. * 手动提交上传
  220. * @param {string}name 文件名称,不传则上传所有type等于waiting和fail的文件
  221. */
  222. upload(name) {
  223. this.lsjFile&&this.lsjFile.upload(name);
  224. },
  225. /**
  226. * @returns {Map} 已选择的文件Map集
  227. */
  228. onchange(files) {
  229. this.$emit('change',files);
  230. this._size = files.size;
  231. return files.size >= this.count ? this.hide() : this.show();
  232. },
  233. /**
  234. * @returns {object} 当前上传中的对象
  235. */
  236. onprogress(item,end=false) {
  237. this.$emit('progress',item);
  238. if (end) {
  239. setTimeout(()=>{
  240. this.$emit('uploadEnd',item);
  241. },0);
  242. }
  243. },
  244. /**
  245. * 移除组件内缓存的某条数据
  246. * @param {string}name 文件名称,不指定默认清除所有文件
  247. */
  248. clear(name) {
  249. this.lsjFile.clear(name);
  250. },
  251. // 创建选择器
  252. create() {
  253. // 若iOS端服务端处理不了跨域就将hybrid目录内的html放到服务端去,并将此处path改成服务器上的地址
  254. let path = '/uni_modules/lsj-upload/hybrid/html/uploadFile.html';
  255. let dom = this.lsjFile.create(path);
  256. // #ifdef H5
  257. this.$refs.lsj.$el.appendChild(dom);
  258. // #endif
  259. // #ifndef APP-PLUS
  260. this.show();
  261. // #endif
  262. // #ifdef APP-PLUS
  263. dom.setStyle({position: this.position});
  264. dom.loadURL(path);
  265. setTimeout(()=>{
  266. // #ifdef APP-NVUE
  267. plus.webview.currentWebview().append(dom);
  268. // #endif
  269. // #ifndef APP-NVUE
  270. this.$root.$scope.$getAppWebview().append(dom);
  271. // #endif
  272. this.show();
  273. },300)
  274. // #endif
  275. },
  276. // 点击选择附件
  277. onClick() {
  278. if (this._size >= this.count) {
  279. this.toast(`只允许上传${this.count}个文件`);
  280. return;
  281. }
  282. // #ifdef MP-WEIXIN
  283. if (!this.isShow) {return;}
  284. let count = this.count - this._size;
  285. this.lsjFile.chooseMessageFile(this.wxFileType,count);
  286. // #endif
  287. },
  288. toast(msg) {
  289. uni.showToast({
  290. title: msg,
  291. icon: 'none'
  292. });
  293. }
  294. }
  295. }
  296. </script>
  297. <style scoped>
  298. .lsj-file {
  299. display: inline-block;
  300. }
  301. .defview {
  302. background-color: #007aff;
  303. color: #fff;
  304. border-radius: 10rpx;
  305. display: flex;
  306. align-items: center;
  307. justify-content: center;
  308. font-size: 28rpx;
  309. }
  310. .hFile {
  311. position: relative;
  312. overflow: hidden;
  313. }
  314. </style>