lsj-upload.vue 7.4 KB

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