index.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /**
  2. * 版本号比较
  3. */
  4. const compareVersion = (v1, v2) => {
  5. v1 = v1.split('.')
  6. v2 = v2.split('.')
  7. const len = Math.max(v1.length, v2.length)
  8. while (v1.length < len) {
  9. v1.push('0')
  10. }
  11. while (v2.length < len) {
  12. v2.push('0')
  13. }
  14. for (let i = 0; i < len; i++) {
  15. const num1 = parseInt(v1[i])
  16. const num2 = parseInt(v2[i])
  17. if (num1 > num2) {
  18. return 1
  19. } else if (num1 < num2) {
  20. return -1
  21. }
  22. }
  23. return 0
  24. }
  25. Component({
  26. externalClasses: ['item-wrap-class'],
  27. options: {
  28. multipleSlots: true
  29. },
  30. properties: {
  31. extraNodes: { // 额外节点
  32. type: Array,
  33. value: []
  34. },
  35. listData: { // 数据源
  36. type: Array,
  37. value: []
  38. },
  39. columns: { // 列数
  40. type: Number,
  41. value: 1
  42. },
  43. topSize: { // 顶部固定高度
  44. type: Number,
  45. value: 0
  46. },
  47. bottomSize: { // 底部固定高度
  48. type: Number,
  49. value: 0
  50. },
  51. itemHeight: { // 每个 item 高度, 用于计算 item-wrap 高度
  52. type: Number,
  53. value: 0
  54. },
  55. scrollTop: { // 页面滚动高度
  56. type: Number,
  57. value: 0
  58. },
  59. },
  60. data: {
  61. /* 未渲染数据 */
  62. baseData: {},
  63. pageMetaSupport: false, // 当前版本是否支持 page-meta 标签
  64. platform: '', // 平台信息
  65. listWxs: [], // wxs 传回的最新 list 数据
  66. rows: 0, // 行数
  67. /* 渲染数据 */
  68. wrapStyle: '', // item-wrap 样式
  69. list: [], // 渲染数据列
  70. dragging: false,
  71. },
  72. methods: {
  73. vibrate() {
  74. if (this.data.platform !== "devtools") wx.vibrateShort();
  75. },
  76. pageScroll(e) {
  77. if (this.data.pageMetaSupport) {
  78. this.triggerEvent("scroll", {
  79. scrollTop: e.scrollTop
  80. });
  81. } else {
  82. wx.pageScrollTo({
  83. scrollTop: e.scrollTop,
  84. duration: 300
  85. });
  86. }
  87. },
  88. drag(e) {
  89. this.setData({
  90. dragging: e.dragging
  91. })
  92. },
  93. listChange(e) {
  94. this.data.listWxs = e.list;
  95. },
  96. itemClick(e) {
  97. let index = e.currentTarget.dataset.index;
  98. let item = this.data.listWxs[index];
  99. this.triggerEvent('click', {
  100. key: item.realKey,
  101. data: item.data,
  102. extra: e.detail
  103. });
  104. },
  105. /**
  106. * 初始化获取 dom 信息
  107. */
  108. initDom() {
  109. let {windowWidth, windowHeight, platform, SDKVersion} = wx.getSystemInfoSync();
  110. let remScale = (windowWidth || 375) / 375;
  111. this.data.pageMetaSupport = compareVersion(SDKVersion, '2.9.0') >= 0;
  112. this.data.platform = platform;
  113. let baseData = {};
  114. baseData.windowHeight = windowHeight;
  115. baseData.realTopSize = this.data.topSize * remScale / 2;
  116. baseData.realBottomSize = this.data.bottomSize * remScale / 2;
  117. baseData.columns = this.data.columns;
  118. baseData.rows = this.data.rows;
  119. const query = this.createSelectorQuery();
  120. query.select(".item").boundingClientRect();
  121. query.select(".item-wrap").boundingClientRect();
  122. query.exec((res) => {
  123. baseData.itemWidth = res[0].width;
  124. baseData.itemHeight = res[0].height;
  125. baseData.wrapLeft = res[1].left;
  126. baseData.wrapTop = res[1].top + this.data.scrollTop;
  127. this.setData({
  128. dragging: false,
  129. baseData
  130. });
  131. });
  132. },
  133. /**
  134. * column 改变时候需要清空 list, 以防页面溢出
  135. */
  136. columnChange() {
  137. this.setData({
  138. list: []
  139. })
  140. this.init();
  141. },
  142. /**
  143. * 初始化函数
  144. * {listData, topSize, bottomSize, itemHeight} 参数改变需要手动调用初始化方法
  145. */
  146. init() {
  147. // 初始必须为true以绑定wxs中的函数,
  148. this.setData({dragging: true});
  149. let delItem = (item, extraNode) => ({
  150. id: item.dragId,
  151. extraNode: extraNode,
  152. fixed: item.fixed,
  153. slot: item.slot,
  154. data: item
  155. });
  156. let {listData, extraNodes} = this.data;
  157. let _list = [], _before = [], _after = [], destBefore = [], destAfter = [];
  158. extraNodes.forEach((item, index) => {
  159. if (item.type === "before") {
  160. _before.push(delItem(item, true));
  161. } else if (item.type === "after") {
  162. _after.push(delItem(item, true));
  163. } else if (item.type === "destBefore") {
  164. destBefore.push(delItem(item, true));
  165. } else if (item.type === "destAfter") {
  166. destAfter.push(delItem(item, true));
  167. }
  168. });
  169. // 遍历数据源增加扩展项, 以用作排序使用
  170. listData.forEach((item, index) => {
  171. destBefore.forEach((i) => {
  172. if (i.data.destKey === index) _list.push(i);
  173. });
  174. _list.push(delItem(item, false));
  175. destAfter.forEach((i) => {
  176. if (i.data.destKey === index) _list.push(i);
  177. });
  178. });
  179. let i = 0, columns = this.data.columns;
  180. let list = (_before.concat(_list, _after) || []).map((item, index) => {
  181. item.realKey = item.extraNode ? -1 : i++; // 真实顺序
  182. item.sortKey = index; // 整体顺序
  183. item.tranX = `${(item.sortKey % columns) * 100}%`;
  184. item.tranY = `${Math.floor(item.sortKey / columns) * 100}%`;
  185. return item;
  186. });
  187. this.data.rows = Math.ceil(list.length / columns);
  188. this.setData({
  189. list,
  190. listWxs: list,
  191. wrapStyle: `height: ${this.data.rows * this.data.itemHeight}rpx`
  192. });
  193. if (list.length === 0) return;
  194. // 异步加载数据时候, 延迟执行 initDom 方法, 防止基础库 2.7.1 版本及以下无法正确获取 dom 信息
  195. setTimeout(() => this.initDom(), 0);
  196. }
  197. },
  198. ready() {
  199. this.init();
  200. }
  201. });