test.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. Component({
  2. options: {
  3. multipleSlots: true,
  4. },
  5. properties: {
  6. // 图片大小,单位px
  7. previewSize: {
  8. type: Number,
  9. value: 100,
  10. },
  11. // 初始化图片数组,用于回显
  12. defaultImgList: {
  13. type: Array,
  14. value: [],
  15. observer(list) {
  16. if (list?.length && !this.data.dragImgList.length) {
  17. const dragImgList = this.getDragImgList(list);
  18. this.setUploaPosition(dragImgList.length);
  19. this.setData({
  20. dragImgList,
  21. });
  22. }
  23. }
  24. },
  25. // 图片上传数量限制
  26. maxCount: {
  27. type: Number,
  28. value: 9,
  29. },
  30. // 列数
  31. columns: {
  32. type: Number,
  33. value: 3,
  34. },
  35. // 图片间隔 单位:px
  36. gap: {
  37. type: Number,
  38. value: 9,
  39. },
  40. // 删除样式
  41. deleteStyle: {
  42. type: String,
  43. value: '',
  44. }
  45. },
  46. data: {
  47. /**
  48. * 拖拽图片列表
  49. * {
  50. * src: string, // 图片路径
  51. * key: number, //
  52. * id: number, // for循环遍历使用, 不会改变, 创建时自增id
  53. * tranX: number, // x轴位移距离
  54. * tranY: number, // y轴位移距离
  55. * }[]
  56. */
  57. dragImgList: [],
  58. containerRes: {
  59. top: 0, // 容器距离页面顶部距离 px
  60. left: 0, // 容器距离页面左边距离 px
  61. width: 0, // 容器宽度 px
  62. height: 0, // 容器高度 px
  63. }, // 拖拽容器属性
  64. currentKey: -1, // 正在拖拽图片的key
  65. currentIndex: -1, // 正在拖拽图片的index
  66. tranX: 0, // 正在拖拽图片移动的x距离
  67. tranY: 0, // 正在拖拽图片移动的y距离
  68. uploadPosition: { // upload上传图标位移距离
  69. tranX: 0,
  70. tranY: 0,
  71. }
  72. },
  73. lifetimes: {
  74. ready() {
  75. this.createSelectorQuery()
  76. .select(".drag-container")
  77. .boundingClientRect(({ top, left }) => {
  78. this.setData({
  79. ['containerRes.top']: top,
  80. ['containerRes.left']: left,
  81. });
  82. }).exec();
  83. }
  84. },
  85. methods: {
  86. /**
  87. * 长按图片
  88. */
  89. longPress(e) {
  90. const index = e.mark.index;
  91. const { pageX, pageY } = e.touches[0];
  92. const { previewSize, containerRes: { top, left } } = this.data;
  93. this.setData({
  94. currentIndex: index,
  95. tranX: pageX - previewSize / 2 - left,
  96. tranY: pageY - previewSize / 2 - top,
  97. });
  98. },
  99. /**
  100. * touchMove
  101. */
  102. touchMove(e) {
  103. // 如果currentIndex < 0,说明并没有触发longPress
  104. if (this.data.currentIndex < 0) {
  105. return;
  106. }
  107. const { pageX, pageY } = e.touches[0];
  108. const { previewSize, containerRes: { top, left } } = this.data;
  109. const tranX = pageX - previewSize / 2 - left;
  110. const tranY = pageY - previewSize / 2 - top;
  111. this.setData({
  112. tranX,
  113. tranY
  114. });
  115. // 对比当前移动的key和停放位置的key,如果不一样就修改位置
  116. const currentKey = e.mark.key;
  117. const moveKey = this.getMoveKey(tranX, tranY);
  118. // 当移动的key和正在停放位置的key相等,就无须处理
  119. if (currentKey === moveKey || this.data.currentKey === currentKey) {
  120. return;
  121. }
  122. this.data.currentKey = currentKey;
  123. this.replace(currentKey, moveKey);
  124. },
  125. /**
  126. * 计算移动中的key
  127. * @param tranX 正在拖拽图片的tranX
  128. * @param tranY 正在拖拽图片的tranY
  129. */
  130. getMoveKey(tranX, tranY) {
  131. const { dragImgList: list, previewSize, columns } = this.data;
  132. const _getPositionNumber = (drag, limit) => {
  133. const positionNumber = Math.round(drag / previewSize);
  134. return positionNumber >= limit ? limit - 1 : positionNumber < 0 ? 0 : positionNumber;
  135. }
  136. const endKey = columns * _getPositionNumber(tranY, Math.ceil(list.length / columns)) + _getPositionNumber(tranX, columns);
  137. return endKey >= list.length ? list.length - 1 : endKey;
  138. },
  139. /**
  140. * 生成拖拽后的新数组
  141. * @param start 拖拽起始的key
  142. * @param end 拖拽结束的key
  143. */
  144. replace(start, end) {
  145. const dragImgList = this.data.dragImgList;
  146. dragImgList.forEach((item) => {
  147. if (start < end) {
  148. if (item.key > start && item.key <= end) item.key--;
  149. else if (item.key === start) item.key = end;
  150. } else if (start > end) {
  151. if (item.key >= end && item.key < start) item.key++;
  152. else if (item.key === start) item.key = end;
  153. }
  154. });
  155. this.getListPosition(dragImgList);
  156. },
  157. /**
  158. * 计算数组的位移位置
  159. * @param list 拖拽图片数组
  160. */
  161. getListPosition(list) {
  162. const { previewSize, columns, gap } = this.data;
  163. const dragImgList = list.map((item) => {
  164. item.tranX = (previewSize + gap) * (item.key % columns);
  165. item.tranY = Math.floor(item.key / columns) * (previewSize + gap);
  166. return item;
  167. })
  168. this.setData({
  169. dragImgList,
  170. });
  171. this.updateEvent(dragImgList);
  172. },
  173. /**
  174. * touchEnd
  175. */
  176. touchEnd() {
  177. this.setData({
  178. tranX: 0,
  179. tranY: 0,
  180. currentIndex: -1,
  181. });
  182. this.data.currentKey = -1;
  183. },
  184. /**
  185. * updateEvent
  186. * @describe 上传删除拖拽后触发事件把列表数据发给页面
  187. */
  188. updateEvent(dragImgList) {
  189. const list = [...dragImgList].sort((a, b) => a.key - b.key).map((item) => item.src);
  190. this.triggerEvent('updateImageList', {
  191. list,
  192. });
  193. },
  194. /**
  195. * 上传图片
  196. */
  197. async uploadImage() {
  198. let { dragImgList, maxCount } = this.data;
  199. try {
  200. const res = await wx.chooseMedia({
  201. count: maxCount - dragImgList.length,
  202. mediaType: ['image'],
  203. });
  204. const imgList = this.getDragImgList(res?.tempFiles?.map(({ tempFilePath }) => tempFilePath) || [], false);
  205. dragImgList = dragImgList.concat(imgList);
  206. this.setUploaPosition(dragImgList.length);
  207. this.setData({
  208. dragImgList,
  209. });
  210. this.updateEvent(dragImgList);
  211. } catch (error) {
  212. console.log(error);
  213. }
  214. },
  215. /**
  216. * 改变图片数量后获取容器宽高
  217. * @parma listLength 数组长度
  218. */
  219. getContainerRect(listLength) {
  220. const { columns, previewSize, maxCount, gap } = this.data;
  221. const number = listLength === maxCount ? listLength : listLength + 1;
  222. const row = Math.ceil(number / columns)
  223. return {
  224. width: columns * previewSize + (columns - 1) * gap,
  225. height: row * previewSize + gap * (row - 1),
  226. };
  227. },
  228. /**
  229. * 根据图片列表生成拖拽列表数据结构
  230. * @param list 图片src列表
  231. * @param init 是否是初始化
  232. */
  233. getDragImgList(list, init = true) {
  234. let { dragImgList, previewSize, columns, gap } = this.data;
  235. return list.map((item, index) => {
  236. const i = (init ? 0 : dragImgList.length) + index;
  237. return {
  238. tranX: (previewSize + gap) * (i % columns),
  239. tranY: Math.floor(i / columns) * (previewSize + gap),
  240. src: item,
  241. id: i,
  242. key: i,
  243. };
  244. });
  245. },
  246. /**
  247. * 修改上传区域位置
  248. * @param listLength 数组长度
  249. */
  250. setUploaPosition(listLength) {
  251. const { previewSize, columns, gap } = this.data;
  252. const uploadPosition = {
  253. tranX: listLength % columns * (previewSize + gap),
  254. tranY: Math.floor(listLength / columns) * (previewSize + gap),
  255. };
  256. const { width, height } = this.getContainerRect(listLength);
  257. this.setData({
  258. uploadPosition,
  259. ['containerRes.width']: width,
  260. ['containerRes.height']: height,
  261. });
  262. },
  263. /**
  264. * 删除图片
  265. */
  266. deleteImg(e) {
  267. const key = e.mark.key;
  268. const list = this.data.dragImgList.filter((item) => item.key !== key);
  269. list.forEach((item) => {
  270. item.key > key && item.key--;
  271. });
  272. this.getListPosition(list);
  273. this.setUploaPosition(list.length);
  274. },
  275. }
  276. })