next-swipe-action.vue 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. <template>
  2. <view class="next-slide" :class="{'next-slide-disabled': disabled}">
  3. <view class="next-slide-left" :style="'position: relative;left:'+left+'rpx'" @touchstart="ontouchstart"
  4. @touchmove="ontouchmove" @touchend="ontouchend">
  5. <slot></slot>
  6. </view>
  7. <view class="next-slide-right">
  8. <view
  9. class="next-btn-item"
  10. v-for="(item,index) in btnGroup"
  11. :key="index"
  12. :style="getStyle(item)"
  13. @click.stop="btnClick(item)">
  14. {{item.name }}
  15. </view>
  16. </view>
  17. </view>
  18. </template>
  19. <script>
  20. const defBtnStyle = {
  21. width: '100rpx',
  22. bgColor: '#f9ae3d',
  23. color: '#FFFFFF',
  24. fontSize: '28rpx',
  25. fontWeight: 300
  26. };
  27. export default {
  28. name: 'NextSwipeAction',
  29. props: {
  30. btnGroup: {
  31. type: Array,
  32. default: () => {
  33. return [{
  34. name: '修改',
  35. style: {
  36. bgColor: '#f9ae3d'
  37. }
  38. }, {
  39. name: '删除',
  40. style: {
  41. bgColor: '#ff4d4f'
  42. }
  43. }]
  44. }
  45. },
  46. //当前列索引
  47. index: {
  48. type: [Number,String],
  49. require: true,
  50. default: 0
  51. },
  52. activeKey:{
  53. type: [Number,String],
  54. default:''
  55. },
  56. //是否禁用
  57. disabled: {
  58. type: Boolean,
  59. default: false
  60. },
  61. // 是否按钮点击后自定重置
  62. btnClickAutoReset: {
  63. type: Boolean,
  64. default: true
  65. }
  66. },
  67. data() {
  68. return {
  69. x: 0,
  70. left: 0,
  71. operation: 0,
  72. height: 0,
  73. screenWidth: 0,
  74. isActive:false,
  75. };
  76. },
  77. watch:{
  78. activeKey(newV){
  79. if(!this.isActive)return;
  80. if(newV != this.index){
  81. this.reset()
  82. }
  83. }
  84. },
  85. mounted() {
  86. this.$nextTick(res => {
  87. const systemInfo = uni.getSystemInfoSync()
  88. this.screenWidth = systemInfo.screenWidth
  89. this.getBtnWidth()
  90. this.getListHeight()
  91. })
  92. },
  93. methods: {
  94. getStyle(item) {
  95. const style = item.style || {};
  96. const styleStr = 'width:'+ (style.width || defBtnStyle.width) +
  97. ';height:' + this.height +
  98. 'rpx;background-color:' + (style.bgColor || defBtnStyle.bgColor) +
  99. ';color:' + (style.color || defBtnStyle.color) +
  100. ';font-size:' + (style.fontSize || defBtnStyle.fontSize) +
  101. 'font-weight:' + (style.fontWeight || defBtnStyle.fontWeight);
  102. return styleStr
  103. },
  104. btnClick(item) {
  105. const it = Object.assign({}, item);
  106. delete it.style;
  107. this.$emit('btnClick', {
  108. index: this.index,
  109. item: it
  110. })
  111. if(this.btnClickAutoReset) {
  112. this.reset()
  113. }
  114. },
  115. //重置方法
  116. reset() {
  117. this.left = 0
  118. this.isActive = false;
  119. },
  120. getBtnWidth() {
  121. const element = uni.createSelectorQuery().in(this).select(".next-slide-right");
  122. element.boundingClientRect(rect => {
  123. this.operation = this.px2rpx(rect.width, this.screenWidth)
  124. }).exec()
  125. },
  126. getListHeight() {
  127. const element = uni.createSelectorQuery().in(this).select(".next-slide-left");
  128. element.boundingClientRect(rect => {
  129. this.height = this.px2rpx(rect.height, this.screenWidth)
  130. }).exec()
  131. },
  132. px2rpx(px, screenWidth) {
  133. return px / (screenWidth / 750)
  134. },
  135. ontouchstart(e) {
  136. if(this.disabled) return
  137. this.x = this.px2rpx(e.touches[0].clientX, this.screenWidth)
  138. },
  139. ontouchmove(e) {
  140. if(this.disabled) return
  141. let clientX = this.x - this.px2rpx(e.touches[0].clientX, this.screenWidth)
  142. if (clientX <= 0) this.left = 0
  143. else if (this.operation <= clientX) this.left = this.operation * -1
  144. else this.left = clientX * -1
  145. },
  146. ontouchend(e) {
  147. if(this.disabled) return
  148. let clientX = this.x - this.px2rpx(e.changedTouches[0].clientX, this.screenWidth)
  149. this.left = clientX > this.operation / 2 ? this.operation * -1 : 0
  150. if(this.left !== 0){
  151. this.isActive = true;
  152. this.$emit('nextSwipeActive', this.index)
  153. }
  154. },
  155. }
  156. }
  157. </script>
  158. <style scoped>
  159. .next-slide {
  160. width: 100%;
  161. position: relative;
  162. overflow: hidden;
  163. }
  164. .next-slide-disabled {
  165. background-color: #333333;
  166. opacity: 0.6;
  167. }
  168. .next-slide-left {
  169. width: 100%;
  170. overflow: hidden;
  171. background-color: #161616;
  172. transition: left 0.2s ease-in-out;
  173. z-index: 999;
  174. }
  175. .next-slide-right {
  176. position: absolute;
  177. top: 0rpx;
  178. right: 0;
  179. z-index: 99;
  180. display: flex;
  181. align-items: center;
  182. justify-content: flex-end;
  183. }
  184. .next-btn-item {
  185. display: flex;
  186. align-items: center;
  187. justify-content: center;
  188. }
  189. </style>