UNPKG

6.53 kBPlain TextView Raw
1<template>
2 <x-cell
3 v-clickoutside:touchstart="swipeMove"
4 @click.native="swipeMove()"
5 @touchstart.native="startDrag"
6 @touchmove.native="onDrag"
7 @touchend.native="endDrag"
8 class="mint-cell-swipe"
9 :title="title"
10 :icon="icon"
11 :label="label"
12 :to="to"
13 :is-link="isLink"
14 ref="cell"
15 :value="value">
16 <div
17 slot="right"
18 class="mint-cell-swipe-buttongroup"
19 ref="right">
20 <a
21 class="mint-cell-swipe-button"
22 v-for="btn in right"
23 :style="btn.style"
24 @click.prevent.stop="btn.handler && btn.handler(), swipeMove()"
25 v-html="btn.content"></a>
26 </div>
27 <div
28 slot="left"
29 class="mint-cell-swipe-buttongroup"
30 ref="left">
31 <a
32 class="mint-cell-swipe-button"
33 v-for="btn in left"
34 :style="btn.style"
35 @click.prevent.stop="btn.handler && btn.handler(), swipeMove()"
36 v-html="btn.content"></a>
37 </div>
38 <slot></slot>
39 <span
40 v-if="$slots.title"
41 slot="title">
42 <slot name="title"></slot>
43 </span>
44 <span
45 v-if="$slots.icon"
46 slot="icon">
47 <slot name="icon"></slot>
48 </span>
49 </x-cell>
50</template>
51
52<script>
53import { once } from 'mint-ui/src/utils/dom';
54import XCell from 'mint-ui/packages/cell/index.js';
55import Clickoutside from 'mint-ui/src/utils/clickoutside';
56if (process.env.NODE_ENV === 'component') {
57 require('mint-ui/packages/cell/style.css');
58}
59
60/**
61 * mt-cell-swipe
62 * @desc 类似 iOS 滑动 Cell 的效果
63 * @module components/cell-swipe
64 *
65 * @example
66 * <mt-cell-swipe
67 * :left=[
68 * {
69 * content: 'text',
70 * style: {color: 'white', backgroundColor: 'red'},
71 * handler(e) => console.log(123)
72 * }
73 * ]
74 * :right=[{ content: 'allowed HTML' }]>
75 * swipe me
76 * </mt-cell-swipe>
77 */
78export default {
79 name: 'mt-cell-swipe',
80
81 components: { XCell },
82
83 directives: { Clickoutside },
84
85 props: {
86 to: String,
87 left: Array,
88 right: Array,
89 icon: String,
90 title: String,
91 label: String,
92 isLink: Boolean,
93 value: {}
94 },
95
96 data() {
97 return {
98 start: { x: 0, y: 0 }
99 };
100 },
101
102 mounted() {
103 this.wrap = this.$refs.cell.$el.querySelector('.mint-cell-wrapper');
104 this.leftElm = this.$refs.left;
105 this.rightElm = this.$refs.right;
106 this.leftWrapElm = this.leftElm.parentNode;
107 this.rightWrapElm = this.rightElm.parentNode;
108 this.leftWidth = this.leftElm.getBoundingClientRect().width;
109 this.rightWidth = this.rightElm.getBoundingClientRect().width;
110
111 this.leftDefaultTransform = this.translate3d(-this.leftWidth - 1);
112 this.rightDefaultTransform = this.translate3d(this.rightWidth);
113
114 this.rightWrapElm.style.webkitTransform = this.rightDefaultTransform;
115 this.leftWrapElm.style.webkitTransform = this.leftDefaultTransform;
116 },
117
118 methods: {
119 resetSwipeStatus() {
120 this.swiping = false;
121 this.opened = true;
122 this.offsetLeft = 0;
123 },
124
125 translate3d(offset) {
126 return `translate3d(${offset}px, 0, 0)`;
127 },
128
129 setAnimations(val) {
130 this.wrap.style.transitionDuration = val;
131 this.rightWrapElm.style.transitionDuration = val;
132 this.leftWrapElm.style.transitionDuration = val;
133 },
134
135 swipeMove(offset = 0) {
136 this.wrap.style.webkitTransform = this.translate3d(offset);
137 this.rightWrapElm.style.webkitTransform = this.translate3d(this.rightWidth + offset);
138 this.leftWrapElm.style.webkitTransform = this.translate3d(-this.leftWidth + offset);
139 offset && (this.swiping = true);
140 },
141
142 swipeLeaveTransition(direction) {
143 setTimeout(() => {
144 this.swipeLeave = true;
145
146 // left
147 if (direction > 0 && -this.offsetLeft > this.rightWidth * 0.4) {
148 this.swipeMove(-this.rightWidth);
149 this.resetSwipeStatus();
150 return;
151 // right
152 } else if (direction < 0 && this.offsetLeft > this.leftWidth * 0.4) {
153 this.swipeMove(this.leftWidth);
154 this.resetSwipeStatus();
155 return;
156 }
157
158 this.swipeMove(0);
159 once(this.wrap, 'webkitTransitionEnd', _ => {
160 this.wrap.style.webkitTransform = '';
161 this.rightWrapElm.style.webkitTransform = this.rightDefaultTransform;
162 this.leftWrapElm.style.webkitTransform = this.leftDefaultTransform;
163 this.swipeLeave = false;
164 this.swiping = false;
165 });
166 }, 0);
167 },
168
169 startDrag(evt) {
170 evt = evt.changedTouches ? evt.changedTouches[0] : evt;
171 this.dragging = true;
172 this.start.x = evt.pageX;
173 this.start.y = evt.pageY;
174 this.direction = '';
175 },
176
177 onDrag(evt) {
178 if (this.opened) {
179 if (!this.swiping) {
180 this.swipeMove(0);
181 this.setAnimations('');
182 }
183 this.opened = false;
184 return;
185 }
186 if (!this.dragging) return;
187
188 let swiping;
189 const e = evt.changedTouches ? evt.changedTouches[0] : evt;
190 const offsetTop = e.pageY - this.start.y;
191 const offsetLeft = this.offsetLeft = e.pageX - this.start.x;
192
193 const y = Math.abs(offsetTop);
194 const x = Math.abs(offsetLeft);
195
196 this.setAnimations('0ms');
197
198 if (this.direction === '') {
199 this.direction = x > y ? 'horizonal' : 'vertical';
200 }
201
202 if (this.direction === 'horizonal') {
203 evt.preventDefault();
204 evt.stopPropagation();
205
206 swiping = !(x < 5 || (x >= 5 && y >= x * 1.73));
207 if (!swiping) return;
208
209 if ((offsetLeft < 0 && -offsetLeft > this.rightWidth) ||
210 (offsetLeft > 0 && offsetLeft > this.leftWidth) ||
211 (offsetLeft > 0 && !this.leftWidth) ||
212 (offsetLeft < 0 && !this.rightWidth)) {
213 } else {
214 this.swipeMove(offsetLeft);
215 }
216 }
217 },
218
219 endDrag() {
220 this.direction = '';
221 this.setAnimations('');
222 if (!this.swiping) return;
223 this.swipeLeaveTransition(this.offsetLeft > 0 ? -1 : 1);
224 }
225 }
226};
227</script>
228
229<style lang="css">
230 @import "../../../src/style/var.css";
231
232 @component-namespace mint {
233 @component cell-swipe {
234 @descendent buttongroup {
235 height: 100%;
236 }
237
238 @descendent button {
239 height: 100%;
240 display: inline-block;
241 padding: 0 10px;
242 line-height: 48px;
243 }
244
245 .mint-cell-wrapper {
246 position: relative;
247 }
248
249 .mint-cell-wrapper,
250 .mint-cell-left,
251 .mint-cell-right {
252 transition: transform 150ms ease-in-out;
253 }
254 }
255 }
256</style>