lsj-upload.vue 8.2 KB

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