swipe-action

swipe-action滑动菜单

组件结构

  1. <template>
  2. <view class="tui-swipeout-wrap">
  3. <view class="tui-swipeout-item" :class="[isShowBtn?'swipe-action-show':'']" @touchstart="handlerTouchstart"
  4. @touchmove="handlerTouchmove" @touchend="handlerTouchend" :style="{transform:'translate(' + position.pageX + 'px,0);'}">
  5. <view class="tui-swipeout-content">
  6. <slot name="content"></slot>
  7. </view>
  8. <view class="tui-swipeout-button-right-group" v-if="actions.length > 0" @touchend.stop="loop">
  9. <view class="tui-swipeout-button-right-item" v-for="(item,index) in actions" :key="index" :style="{background:item.background || '#f7f7f7',color:item.color,width:item.width+'px'}"
  10. :data-index="index" @tap="handlerButton">
  11. <image :src="item.icon" v-if="item.icon" :style="{width:px(item.imgWidth),height:px(item.imgHeight)}"></image>
  12. <text :style="{fontSize:px(item.fontsize)}">{{item.name}}</text>
  13. </view>
  14. </view>
  15. <!--actions长度设置为0,可直接传按钮进来-->
  16. <view class="tui-swipeout-button-right-group" @touchend.stop="loop" @tap="handlerParentButton" v-if="actions.length === 0"
  17. :style="{width:operateWidth+'px',right:'-'+operateWidth+'px'}">
  18. <slot name="button"></slot>
  19. </view>
  20. </view>
  21. <view v-if="isShowBtn && showMask" class="swipe-action_mask" @tap="closeButtonGroup" @touchmove.stop="closeButtonGroup" />
  22. </view>
  23. </template>

组件脚本

  1. <script>
  2. export default {
  3. name: "tuiSwipeAction",
  4. props: {
  5. // name: '删除',
  6. // color: '#fff',
  7. // fontsize: 32,//单位upx
  8. // width: 80, //单位px
  9. // icon: 'like.png',//此处为图片地址
  10. // background: '#ed3f14'
  11. actions: {
  12. type: Array,
  13. default: []
  14. },
  15. //是否可关闭,默认可关闭,可以单独控制
  16. closable: {
  17. type: Boolean,
  18. default: true
  19. },
  20. //设为false,可以滑动多行不关闭菜单
  21. showMask: {
  22. type: Boolean,
  23. default: true
  24. },
  25. operateWidth: {
  26. type: Number,
  27. default: 80
  28. },
  29. params: {
  30. type: Object,
  31. default: {}
  32. }
  33. },
  34. watch: {
  35. actions(newValue, oldValue) {
  36. this.updateButtonSize()
  37. }
  38. },
  39. data() {
  40. return {
  41. //start position
  42. tStart: {
  43. pageX: 0,
  44. pageY: 0
  45. },
  46. //限制滑动距离
  47. limitMove: 0,
  48. //move position
  49. position: {
  50. pageX: 0,
  51. pageY: 0
  52. },
  53. isShowBtn: false
  54. };
  55. },
  56. // #ifdef H5
  57. mounted() {
  58. this.updateButtonSize()
  59. },
  60. // #endif
  61. onReady() {
  62. this.updateButtonSize()
  63. },
  64. methods: {
  65. swipeDirection(x1, x2, y1, y2) {
  66. return Math.abs(x1 - x2) >=
  67. Math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down')
  68. },
  69. //阻止事件冒泡
  70. loop() {},
  71. updateButtonSize() {
  72. const actions = this.actions;
  73. if (actions.length > 0) {
  74. const query = uni.createSelectorQuery().in(this);
  75. let limitMovePosition = 0;
  76. actions.forEach(item => {
  77. limitMovePosition += item.width || 0;
  78. });
  79. this.limitMove = limitMovePosition;
  80. } else {
  81. this.limitMove = this.operateWidth;
  82. }
  83. },
  84. handlerTouchstart(event) {
  85. const touches = event.touches ? event.touches[0] : {};
  86. const tStart = this.tStart;
  87. if (touches) {
  88. for (let i in tStart) {
  89. if (touches[i]) {
  90. tStart[i] = touches[i];
  91. }
  92. }
  93. }
  94. },
  95. swipper(touches) {
  96. const start = this.tStart;
  97. const spacing = {
  98. pageX: touches.pageX - start.pageX,
  99. pageY: touches.pageY - start.pageY
  100. }
  101. if (this.limitMove < Math.abs(spacing.pageX)) {
  102. spacing.pageX = -this.limitMove;
  103. }
  104. this.position = spacing
  105. },
  106. handlerTouchmove(event) {
  107. const start = this.tStart;
  108. const touches = event.touches ? event.touches[0] : {};
  109. if (touches) {
  110. const direction = this.swipeDirection(start.pageX, touches.pageX, start.pageY, touches.pageY);
  111. if (direction === 'Left') {
  112. this.swipper(touches);
  113. }
  114. }
  115. },
  116. handlerTouchend(event) {
  117. const start = this.tStart;
  118. const touches = event.changedTouches ? event.changedTouches[0] : {};
  119. if (touches) {
  120. const direction = this.swipeDirection(start.pageX, touches.pageX, start.pageY, touches.pageY);
  121. const spacing = {
  122. pageX: touches.pageX - start.pageX,
  123. pageY: touches.pageY - start.pageY
  124. }
  125. if (Math.abs(spacing.pageX) >= 40 && direction === "Left") {
  126. spacing.pageX = spacing.pageX < 0 ? -this.limitMove : this.limitMove;
  127. this.isShowBtn = true
  128. } else {
  129. spacing.pageX = 0;
  130. }
  131. this.position = spacing
  132. }
  133. },
  134. handlerButton(event) {
  135. if (this.closable) {
  136. this.closeButtonGroup();
  137. }
  138. const dataset = event.currentTarget.dataset;
  139. this.$emit('click', {
  140. index: Number(dataset.index),
  141. item: this.params
  142. })
  143. },
  144. closeButtonGroup() {
  145. this.position = {
  146. pageX: 0,
  147. pageY: 0
  148. };
  149. this.isShowBtn = false
  150. },
  151. //控制自定义组件
  152. handlerParentButton(event) {
  153. if (this.closable) {
  154. this.closeButtonGroup();
  155. }
  156. },
  157. px(num) {
  158. return uni.upx2px(num) + "px"
  159. }
  160. }
  161. }
  162. </script>

组件样式

  1. ... 此处省略n

脚本说明

  1. props:
  2. "actions" : 按钮信息,类型:"Array",默认值:[],数组内容:
  3. [
  4. name: '删除',
  5. color: '#fff',
  6. fontsize: 32,//单位upx
  7. width: 80, //单位px
  8. icon: 'like.png',//此处为图片地址
  9. background: '#ed3f14'
  10. ]
  11. "closable" : 是否可关闭,默认可关闭,可以单独控制,类型:"Boolean",默认值:true
  12. "showMask" : 是否显示遮罩, 设为false,可以滑动多行不关闭菜单,类型:"Boolean",默认值:true
  13. "operateWidth" : 按钮宽度,类型:"Number",默认值:80px
  14. "params" : 参数,类型:"Object",默认值:{}
  15. methods:
  16. "handlerButton":按钮点击事件
  17. "closeButtonGroup":关闭滑动

示例

  1. ... 此处省略n行,下载源码查看