tn-drag.vue 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. <template>
  2. <view
  3. class="tn-drag-class tn-drag"
  4. :style="{
  5. height: wrapHeight + 'rpx'
  6. }"
  7. :list="listData"
  8. :basedata="baseData"
  9. :change:list="wxs.listObserver"
  10. :change:basedata="wxs.baseDataObserver"
  11. >
  12. <!-- #ifdef MP-WEIXIN -->
  13. <view
  14. v-for="(item, index) in listData"
  15. :key="item.id"
  16. class="tn-drag__item"
  17. :style="{
  18. width: 100 / columns + '%',
  19. height: itemHeight + 'rpx'
  20. }"
  21. :data-index="index"
  22. :data-basedata="baseData"
  23. :data-edit="edit"
  24. @longpress="wxs.longPress"
  25. @touchstart="wxs.touchStart"
  26. :catch:touchmove="dragging?wxs.touchMove:''"
  27. :catch:touchend="dragging?wxs.touchEnd:''"
  28. >
  29. <slot :entity="item.data" :fixed="item.fixed" :index="index" :height="itemHeight" :isEdit="edit"></slot>
  30. </view>
  31. <!-- #endif -->
  32. <!-- #ifndef MP-WEIXIN -->
  33. <view
  34. v-for="(item, index) in listData"
  35. :key="item.id"
  36. class="tn-drag__item"
  37. :style="{
  38. width: 100 / columns + '%',
  39. height: itemHeight + 'rpx'
  40. }"
  41. @longpress="wxs.longPress"
  42. :data-index="index"
  43. :data-basedata="baseData"
  44. :data-edit="edit"
  45. @touchstart="wxs.touchStart"
  46. @touchmove="wxs.touchMove"
  47. @touchend="wxs.touchEnd"
  48. >
  49. <slot :entity="item.data" :fixed="item.fixed" :index="index" :height="itemHeight" :isEdit="edit"></slot>
  50. </view>
  51. <!-- #endif -->
  52. </view>
  53. </template>
  54. <script src="./index.wxs" lang="wxs" module="wxs"></script>
  55. <script>
  56. export default {
  57. name: 'tn-drag',
  58. props: {
  59. // 数据源
  60. // 如果属性中包含fixed,则标识当前数据不允许拖动
  61. list: {
  62. type: Array,
  63. default () {
  64. return []
  65. }
  66. },
  67. // 是否允许拖动编辑
  68. edit: {
  69. type: Boolean,
  70. default: true
  71. },
  72. // 列数
  73. columns: {
  74. type: Number,
  75. default: 3
  76. },
  77. // item元素高度, 单位rpx
  78. itemHeight: {
  79. type: Number,
  80. default: 0
  81. },
  82. // 当前父元素滚动的高度
  83. scrollTop: {
  84. type: Number,
  85. default: 0
  86. }
  87. },
  88. computed: {
  89. wrapHeight() {
  90. return this.rows * this.itemHeight
  91. }
  92. },
  93. data() {
  94. return {
  95. // 未渲染前节点数据
  96. baseData: {},
  97. // 拖动后的数据
  98. dragData: [],
  99. // 行数
  100. rows: 0,
  101. // 渲染数据
  102. listData: [],
  103. // 标记是否正在拖动
  104. dragging: false
  105. }
  106. },
  107. watch: {
  108. list(val) {
  109. this.listData = []
  110. this.$nextTick(() => {
  111. this.init()
  112. })
  113. },
  114. columns(val) {
  115. this.listData = []
  116. this.$nextTick(() => {
  117. this.init()
  118. })
  119. }
  120. },
  121. mounted() {
  122. this.$nextTick(() => {
  123. this.init()
  124. })
  125. },
  126. methods: {
  127. // 初始化
  128. init() {
  129. this.dragging = true
  130. const initDragItem = item => {
  131. const obj = {
  132. ...item
  133. }
  134. const fixed = obj?.fixed || false
  135. delete obj["fixed"]
  136. return {
  137. id: this.unique(),
  138. fixed,
  139. data: {
  140. ...obj
  141. }
  142. }
  143. }
  144. let i = 0
  145. const listData = (this.list || []).map((item, index) => {
  146. let listItem = initDragItem(item)
  147. // 真实排序
  148. listItem.realKey = i++
  149. // 整体排序
  150. listItem.sortKey = index
  151. listItem.translateX = `${(listItem.sortKey % this.columns) * 100}%`
  152. listItem.translateY = `${Math.floor(listItem.sortKey / this.columns) * 100}%`
  153. return listItem
  154. })
  155. this.rows = Math.ceil(listData.length / this.columns)
  156. this.listData = listData
  157. this.dragData = listData
  158. if (listData.length === 0) return
  159. // console.log(listData);
  160. // 初始化dom元素
  161. this.$nextTick(() => {
  162. this.initRect()
  163. })
  164. },
  165. // 初始化dom元素
  166. initRect() {
  167. const {
  168. windowWidth,
  169. windowHeight
  170. } = uni.getSystemInfoSync()
  171. let baseData = {}
  172. baseData.windowHeight = windowHeight
  173. baseData.realTopSize = 0
  174. baseData.realBottomSize = 0
  175. baseData.columns = this.columns
  176. baseData.rows = this.rows
  177. const query = uni.createSelectorQuery().in(this)
  178. query.select('.tn-drag').boundingClientRect()
  179. query.select('.tn-drag__item').boundingClientRect()
  180. query.exec(res => {
  181. if (!res) {
  182. setTimeout(() => {
  183. this.initRect()
  184. }, 10)
  185. return
  186. }
  187. baseData.itemWidth = res[1].width
  188. baseData.itemHeight = res[1].height
  189. baseData.left = res[0].left
  190. baseData.top = res[0].top + this.scrollTop
  191. this.dragging = false
  192. this.baseData = baseData
  193. })
  194. },
  195. // 触发震动
  196. vibrate() {
  197. uni.vibrateShort()
  198. },
  199. // 滚动到指定的位置
  200. pageScroll(e) {
  201. uni.pageScrollTo({
  202. scrollTop: e.scrollTop,
  203. duration: 0
  204. })
  205. },
  206. // 修改拖动状态
  207. drag(e) {
  208. this.dragging = e.dragging
  209. },
  210. // 拖拽数据发生改变
  211. listDataChange(e) {
  212. this.dragData = e.data
  213. },
  214. // item被点击
  215. itemClick(index) {
  216. const item = this.dragData[index]
  217. this.$emit('click', {
  218. key: item.realKey,
  219. data: item.data
  220. })
  221. },
  222. // 拖拽结束事件
  223. sortEnd(e) {
  224. this.$emit('end', {
  225. data: e.data
  226. })
  227. },
  228. // 排序发生改变事件
  229. change(e) {
  230. this.$emit('change', {
  231. data: e.data
  232. })
  233. },
  234. // 生成元素唯一id
  235. unique(n = 6) {
  236. let id = ''
  237. for (let i = 0; i < n; i++) id += Math.floor(Math.random() * 10)
  238. return 'tn_' + new Date().getTime() + id
  239. }
  240. }
  241. }
  242. </script>
  243. <style lang="scss" scoped>
  244. .tn-drag {
  245. position: relative;
  246. &__item {
  247. position: absolute;
  248. z-index: 2;
  249. top: 0;
  250. left: 0;
  251. }
  252. &__transition {
  253. transition: transform 0.25s !important;
  254. }
  255. &__current {
  256. z-index: 10 !important;
  257. }
  258. &__fixed {
  259. z-index: 1 !important;
  260. }
  261. }
  262. </style>