lsj-upload.vue 7.6 KB

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