index.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. <template>
  2. <view>
  3. <uni-file-picker @select="select" mode="grid" @delete="deletefile" v-model="fileList" :limit="maxSize"
  4. file-mediatype="image" :image-styles="imageStyles"></uni-file-picker>
  5. </view>
  6. </template>
  7. <script>
  8. export default {
  9. name: 'MUpload',
  10. data() {
  11. return {
  12. fileList: [],
  13. // 提交用原始数据(相对路径);组件内维护,避免并行上传时 prop 回传延迟导致丢图
  14. innerList: [],
  15. imageStyles: {
  16. width: 100,
  17. height: 100,
  18. border: {
  19. radius: '5px'
  20. }
  21. }
  22. }
  23. },
  24. props: {
  25. maxSize: {
  26. type: Number,
  27. default: 1
  28. },
  29. value: {
  30. type: Array,
  31. default() {
  32. return []
  33. }
  34. }
  35. },
  36. watch: {
  37. value: {
  38. deep: true,
  39. handler: function (newV) {
  40. // 数据为空的三种情况
  41. if (newV === null || newV === '' || newV === undefined) {
  42. this.fileList = []
  43. this.innerList = []
  44. return
  45. }
  46. // 同步内部数据源,再转展示数据;新数组引用才能触发 uni-file-picker 刷新
  47. this.innerList = newV
  48. this.fileList = this.toDisplayList(newV)
  49. }
  50. }
  51. },
  52. methods: {
  53. // 生成展示数据:相对路径转完整地址;克隆处理,不修改提交用的原始数据,避免重复拼接前缀
  54. toDisplayList(list) {
  55. return (list || []).map(item => {
  56. const data = Object.assign({}, item)
  57. if (data.url && data.url.substr(0, 4) !== 'http') {
  58. data.url = this.$BaseTool.UserUtil.getFileUrl(data.url)
  59. }
  60. return data
  61. })
  62. },
  63. deletefile(e) {
  64. // e.tempFilePath 为展示用的完整地址,按原始 url 后缀匹配,同步删除提交数据中的对应项
  65. const newValue = (this.innerList || []).filter(item => {
  66. return !(item.url && e.tempFilePath && e.tempFilePath.endsWith(item.url))
  67. })
  68. this.innerList = newValue
  69. this.$emit('input', newValue)
  70. this.$emit('change', newValue)
  71. },
  72. select(e) {
  73. // 根据所选图片的个数,多次调用上传函数
  74. console.log(e)
  75. let promises = []
  76. for (let i = 0; i < e.tempFilePaths.length; i++) {
  77. const promise = this.uploadFiles(e.tempFilePaths, i)
  78. promises.push(promise)
  79. }
  80. Promise.all(promises).then(() => { })
  81. },
  82. // 上传函数
  83. async uploadFiles(tempFilePaths, i) {
  84. let that = this
  85. await uni.uploadFile({
  86. url: that.$BaseTool.UserUtil.getUploadUrl(),
  87. filePath: tempFilePaths[i],
  88. name: 'file',
  89. header: {
  90. Authorization: that.$BaseTool.UserUtil.getToken(tempFilePaths[0])
  91. },
  92. success: res => {
  93. let data = JSON.parse(res.data) //返回的是字符串,需要转成对象格式
  94. const reg = new RegExp('[;,。!?;,]')
  95. if (reg.test(res.data.fileName)) {
  96. uni.showToast({ icon: 'none', title: '文件名包含非法字符!' })
  97. } else {
  98. // 回传原始文件实体(相对路径),保证提交数据不变;
  99. // 新数组引用触发父组件更新 -> watch 转为展示数据 -> 列表刷新展示
  100. const newValue = (that.innerList || []).concat([data.data])
  101. that.innerList = newValue
  102. that.$emit('input', newValue)
  103. that.$emit('change', newValue)
  104. }
  105. },
  106. fail: () => {
  107. uni.showToast({ icon: 'none', title: '上传失败!' })
  108. }
  109. })
  110. }
  111. }
  112. }
  113. </script>
  114. <style></style>