good-action.vue 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. <template>
  2. <movable-area class="u-swipe-action" :style="{backgroundColor: bgColor}">
  3. <movable-view
  4. class="u-swipe-view"
  5. @change="change"
  6. @touchend="touchend"
  7. @touchstart="touchstart"
  8. direction="horizontal"
  9. :disabled="disabled"
  10. :x="moveX"
  11. :style="{
  12. width: movableViewWidth
  13. }"
  14. >
  15. <view class="u-swipe-content"><slot></slot></view>
  16. <view
  17. class="u-swipe-del dir-top-wrap main-center"
  18. @tap.stop="share"
  19. :style="{
  20. width: innerBtnWidth/2 + 'px',
  21. 'background-color': theme.background_s
  22. }"
  23. >
  24. <text class="u-btn-text" :style="{'color': theme.color}">分享</text>
  25. </view>
  26. <view
  27. class="u-swipe-del dir-top-wrap main-center"
  28. @tap.stop="del"
  29. :style="{
  30. width: innerBtnWidth / 2 + 'px',
  31. 'background-color': theme.background
  32. }"
  33. >
  34. <text class="u-btn-text">删除</text>
  35. </view>
  36. </movable-view>
  37. </movable-area>
  38. </template>
  39. <script>
  40. export default {
  41. props: {
  42. btnText: {
  43. type: String,
  44. default: '删除'
  45. },
  46. btnBgColor: {
  47. type: String,
  48. default: '#ff0033'
  49. },
  50. index: {
  51. type: [Number, String],
  52. default: ''
  53. },
  54. btnWidth: {
  55. type: [String, Number],
  56. default: 200
  57. },
  58. disabled: {
  59. type: Boolean,
  60. default: false
  61. },
  62. show: {
  63. type: Boolean,
  64. default: false
  65. },
  66. bgColor: {
  67. type: String,
  68. default: '#ffffff'
  69. },
  70. theme: {
  71. type: Object
  72. },
  73. touch: {
  74. type: Boolean
  75. }
  76. },
  77. watch: {
  78. show: {
  79. immediate: true,
  80. handler(nVal, oVal) {
  81. if(nVal) {
  82. this.open();
  83. } else {
  84. this.close();
  85. }
  86. }
  87. }
  88. },
  89. data() {
  90. return {
  91. moveX: 0,
  92. scrollX: 0,
  93. status: false,
  94. movableAreaWidth: 0,
  95. elId: this.guid()
  96. }
  97. },
  98. computed: {
  99. movableViewWidth() {
  100. return (this.movableAreaWidth + this.innerBtnWidth) + 'px';
  101. },
  102. innerBtnWidth() {
  103. return uni.upx2px(this.btnWidth);
  104. },
  105. },
  106. mounted() {
  107. this.getActionRect();
  108. },
  109. methods: {
  110. guid(len = 32, firstU = true, radix = null) {
  111. let chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
  112. let uuid = [];
  113. radix = radix || chars.length;
  114. if (len) {
  115. for (let i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
  116. } else {
  117. let r;
  118. uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
  119. uuid[14] = '4';
  120. for (let i = 0; i < 36; i++) {
  121. if (!uuid[i]) {
  122. r = 0 | Math.random() * 16;
  123. uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
  124. }
  125. }
  126. }
  127. if(firstU) {
  128. uuid.shift();
  129. return 'u' + uuid.join('');
  130. } else {
  131. return uuid.join('');
  132. }
  133. },
  134. del() {
  135. this.status = false;
  136. this.moveX = 0;
  137. this.$emit('del', this.index);
  138. },
  139. share() {
  140. this.status = false;
  141. this.moveX = 0;
  142. this.$emit('share', this.index);
  143. },
  144. change(e) {
  145. this.scrollX = e.detail.x;
  146. },
  147. close() {
  148. this.moveX = 0;
  149. this.status = false;
  150. },
  151. open() {
  152. if(this.disabled) return ;
  153. this.moveX = - this.btnWidth;
  154. this.status = true;
  155. },
  156. touchend() {
  157. this.moveX = this.scrollX;
  158. this.$nextTick(function(){
  159. if(this.status == false) {
  160. if(this.scrollX <= -this.innerBtnWidth / 3) {
  161. this.moveX = -this.innerBtnWidth;
  162. this.status = true;
  163. this.emitOpenEvent();
  164. uni.vibrateShort();
  165. } else {
  166. this.moveX = 0;
  167. this.status = false;
  168. this.emitCloseEvent();
  169. }
  170. } else {
  171. if(this.scrollX > -this.innerBtnWidth * 2 / 3) {
  172. this.moveX = 0;
  173. this.$nextTick(() => {
  174. this.moveX = 101;
  175. })
  176. this.status = false;
  177. this.emitCloseEvent();
  178. } else {
  179. this.moveX = -this.innerBtnWidth;
  180. this.status = true;
  181. this.emitOpenEvent();
  182. }
  183. }
  184. })
  185. },
  186. emitOpenEvent() {
  187. this.$emit('open', this.index);
  188. },
  189. emitCloseEvent() {
  190. this.$emit('close', this.index);
  191. },
  192. touchstart() {
  193. },
  194. getActionRect() {
  195. const query = uni.createSelectorQuery().in(this);
  196. query.select('.u-swipe-action').boundingClientRect(data => {
  197. this.movableAreaWidth = data.width;
  198. }).exec();
  199. }
  200. }
  201. }
  202. </script>
  203. <style scoped lang="scss">
  204. .u-swipe-action {
  205. width: auto;
  206. height: initial;
  207. position: relative;
  208. overflow: hidden;
  209. }
  210. .u-swipe-view {
  211. display: flex;
  212. height: initial;
  213. position: relative; /* 这一句很关键,覆盖默认的绝对定位 */
  214. }
  215. .u-swipe-content {
  216. flex: 1;
  217. }
  218. .u-swipe-del {
  219. position: relative;
  220. font-size: 30rpx;
  221. color: #ffffff;
  222. }
  223. .u-btn-text {
  224. font-size: 30upx;
  225. text-align: center;
  226. }
  227. </style>