You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

314 lines
7.2 KiB

  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. // nvue不支持跟随窗口滚动
  46. position: {
  47. type: String,
  48. // #ifdef APP-NVUE
  49. default: 'absolute',
  50. // #endif
  51. // #ifndef APP-NVUE
  52. default: 'static',
  53. // #endif
  54. },
  55. },
  56. data() {
  57. return {
  58. }
  59. },
  60. watch: {
  61. option(v) {
  62. // #ifdef APP-PLUS
  63. this.lsjFile&&this.show();
  64. // #endif
  65. }
  66. },
  67. updated() {
  68. // #ifdef APP-PLUS
  69. if (this.isShow) {
  70. this.lsjFile&&this.show();
  71. }
  72. // #endif
  73. },
  74. computed: {
  75. getStyles() {
  76. let styles = {
  77. width: this.width,
  78. height: this.height
  79. }
  80. if (this.position == 'absolute') {
  81. styles['top'] = this.top
  82. styles['bottom'] = this.bottom
  83. styles['left'] = this.left
  84. styles['right'] = this.right
  85. styles['position'] = 'fixed'
  86. }
  87. return styles
  88. }
  89. },
  90. mounted() {
  91. this.$nextTick(()=>{
  92. this._size = 0;
  93. this.lsjFile = new LsjFile({
  94. debug: this.debug,
  95. id: this.childId,
  96. width: this.width,
  97. height: this.height,
  98. option: this.option,
  99. instantly: this.instantly,
  100. // 限制条件
  101. prohibited: {
  102. // 大小
  103. size: this.size,
  104. // 允许上传的格式
  105. formats: this.formats,
  106. // 限制选择的格式
  107. accept: this.accept,
  108. count: this.count
  109. },
  110. onchange: this.onchange,
  111. onprogress: this.onprogress,
  112. });
  113. this.create();
  114. })
  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. this.isShow = true;
  186. // #ifdef APP-PLUS
  187. this.lsjFile&&this.getDomStyles(styles => {
  188. this.lsjFile.dom.setStyle(styles)
  189. });
  190. // #endif
  191. // #ifdef H5
  192. this.lsjFile.dom.style.display = 'inline'
  193. // #endif
  194. },
  195. hide() {
  196. this.isShow = false;
  197. // #ifdef APP-PLUS
  198. this.lsjFile&&this.lsjFile.dom.setStyle({
  199. top: '-500px',
  200. left:'0px',
  201. width: '1px',
  202. height: '1px',
  203. });
  204. // #endif
  205. // #ifdef H5
  206. this.lsjFile.dom.style.display = 'none'
  207. // #endif
  208. },
  209. /**
  210. * 手动提交上传
  211. * @param {string}name 文件名称,不传则上传所有type等于waiting和fail的文件
  212. */
  213. upload(name) {
  214. this.lsjFile&&this.lsjFile.upload(name);
  215. },
  216. /**
  217. * @returns {Map} 已选择的文件Map集
  218. */
  219. onchange(files) {
  220. this.$emit('change',files);
  221. this._size = files.size;
  222. return files.size >= this.count ? this.hide() : this.show();
  223. },
  224. /**
  225. * @returns {object} 当前上传中的对象
  226. */
  227. onprogress(item,end=false) {
  228. this.$emit('progress',item);
  229. if (end) {
  230. setTimeout(()=>{
  231. this.$emit('uploadEnd',item);
  232. },0);
  233. }
  234. },
  235. /**
  236. * 移除组件内缓存的某条数据
  237. * @param {string}name 文件名称,不指定默认清除所有文件
  238. */
  239. clear(name) {
  240. this.lsjFile.clear(name);
  241. },
  242. // 创建选择器
  243. create() {
  244. // 若iOS端服务端处理不了跨域就将hybrid目录内的html放到服务端去,并将此处path改成服务器上的地址
  245. let path = '/uni_modules/lsj-upload/hybrid/html/uploadFile.html';
  246. let dom = this.lsjFile.create(path);
  247. // #ifdef H5
  248. this.$refs.lsj.$el.appendChild(dom);
  249. // #endif
  250. // #ifndef APP-PLUS
  251. this.show();
  252. // #endif
  253. // #ifdef APP-PLUS
  254. dom.setStyle({position: this.position});
  255. dom.loadURL(path);
  256. setTimeout(()=>{
  257. // #ifdef APP-NVUE
  258. plus.webview.currentWebview().append(dom);
  259. // #endif
  260. // #ifndef APP-NVUE
  261. this.$root.$scope.$getAppWebview().append(dom);
  262. // #endif
  263. this.show();
  264. },300)
  265. // #endif
  266. },
  267. // 点击选择附件
  268. onClick() {
  269. if (this._size >= this.count) {
  270. this.toast(`只允许上传${this.count}个文件`);
  271. return;
  272. }
  273. // #ifdef MP-WEIXIN
  274. if (!this.isShow) {return;}
  275. let count = this.count - this._size;
  276. this.lsjFile.chooseMessageFile(this.wxFileType,count);
  277. // #endif
  278. },
  279. toast(msg) {
  280. uni.showToast({
  281. title: msg,
  282. icon: 'none'
  283. });
  284. }
  285. }
  286. }
  287. </script>
  288. <style scoped>
  289. .lsj-file {
  290. display: inline-block;
  291. }
  292. .defview {
  293. background-color: #007aff;
  294. color: #fff;
  295. border-radius: 10rpx;
  296. display: flex;
  297. align-items: center;
  298. justify-content: center;
  299. font-size: 28rpx;
  300. }
  301. .hFile {
  302. position: relative;
  303. overflow: hidden;
  304. }
  305. </style>