├── README.md
├── fingerDemo.vue
├── index.html
└── vue-finger.js
/README.md:
--------------------------------------------------------------------------------
1 | # vue-finger
2 | 基于腾讯AlloyFinger的vue 2.0手势插件 AlloyFinger:http://alloyteam.github.io/AlloyFinger/
3 |
4 | 所有手势事件
5 | v-tap:点击事件
6 | v-singleTap:单击事件,和tap的区别是相差250ms
7 | v-longTap:长按事件,当点击时长超过750ms时候触发
8 | v-doubleTap:双击事件
9 | v-pressMove:拖拽移动事件
10 | v-multipointStart:多点触控事件开始事件
11 | v-multipointEnd:多点触控事件结束事件
12 | v-swipe:滑动事件
13 | v-rotate:旋转事件
14 | v-pinch:缩放事件
15 |
16 | 使用示例:
17 | 见fingerDemo,在项目中使用的时候,在main.js中导入、vue.use(),然后在子组件中就可以直接用v-tap="{methods:func , arg: args}"的方式使用
18 |
--------------------------------------------------------------------------------
/fingerDemo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

14 |
{{ msg }}
15 |
16 |
17 |
97 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
helloword
2 |
--------------------------------------------------------------------------------
/vue-finger.js:
--------------------------------------------------------------------------------
1 | function getLen (v) {
2 | if (isNaN(v.x) || isNaN(v.y)) {
3 | return 0
4 | } else {
5 | return Math.sqrt(v.x * v.x + v.y * v.y)
6 | }
7 | }
8 | function dot (v1, v2) {
9 | return v1.x * v2.x + v1.y * v2.y
10 | }
11 | function getAngle (v1, v2) {
12 | var mr = getLen(v1) * getLen(v2)
13 | if (mr === 0) return 0
14 | var r = dot(v1, v2) / mr
15 | if (r > 1) r = 1
16 | return Math.acos(r)
17 | }
18 | function cross (v1, v2) {
19 | return v1.x * v2.y - v2.x * v1.y
20 | }
21 | function getRotateAngle (v1, v2) {
22 | var angle = getAngle(v1, v2)
23 | if (cross(v1, v2) > 0) {
24 | angle *= -1
25 | }
26 | return angle * 180 / Math.PI
27 | }
28 | var vueFinger = {}
29 | vueFinger.install = function (Vue, options) {
30 | var self = this
31 | self.config = {
32 | preV: {x: null, y: null},
33 | pinchStartLen: null,
34 | scale: 1,
35 | isDoubleTap: false,
36 | touchStart: function () {},
37 | touchMove: function () {},
38 | touchEnd: function () {},
39 | touchCancel: function () {},
40 | tap: function () {},
41 | singleTap: function () {},
42 | longTap: function () {},
43 | doubleTap: function () {},
44 | pressMove: function () {},
45 | multipointStart: function () {},
46 | multipointEnd: function () {},
47 | swipe: function () {},
48 | pinch: function () {},
49 | rotate: function () {},
50 | delta: null,
51 | last: null,
52 | now: null,
53 | tapTimeout: null,
54 | touchTimeout: null,
55 | longTapTimeout: null,
56 | swipeTimeout: null,
57 | x1: null,
58 | x2: null,
59 | y1: null,
60 | y2: null,
61 | preTapPosition: { x: null, y: null }
62 | }
63 | self.start = function (e) {
64 | if (!e.touches) return
65 | e.preventDefault()
66 | self.config.now = Date.now()
67 | self.config.x1 = e.touches[0].pageX
68 | self.config.y1 = e.touches[0].pageY
69 | self.config.delta = self.config.now - (self.config.last || self.config.now)
70 | self.config.touchStart(e)
71 | if (self.config.preTapPosition.x !== null) {
72 | self.config.isDoubleTap = (self.config.delta > 0 && self.config.delta <= 250 &&
73 | Math.abs(self.config.preTapPosition.x - self.config.x1) < 30 &&
74 | Math.abs(self.config.preTapPosition.y - self.config.y1) < 30)
75 | }
76 | self.config.preTapPosition.x = self.config.x1
77 | self.config.preTapPosition.y = self.config.y1
78 | self.config.last = self.config.now
79 | var preV = self.config.preV
80 | var len = e.touches.length
81 | if (len > 1) {
82 | self._cancelLongTap()
83 | var v = { x: e.touches[1].pageX - self.config.x1, y: e.touches[1].pageY - self.config.y1 }
84 | preV.x = v.x
85 | preV.y = v.y
86 | self.config.pinchStartLen = getLen(preV)
87 | self.config.multipointStart(e)
88 | }
89 | self.config.longTapTimeout = setTimeout(function () {
90 | self.config.longTap(e)
91 | }, 750)
92 | }
93 | self.move = function (e) {
94 | if (!e.touches) return
95 | e.preventDefault()
96 | var preV = self.config.preV
97 | var len = e.touches.length
98 | var currentX = e.touches[0].pageX
99 | var currentY = e.touches[0].pageY
100 | self.config.isDoubleTap = false
101 | if (len > 1) {
102 | var v = { x: e.touches[1].pageX - currentX, y: e.touches[1].pageY - currentY }
103 | if (preV.x !== null) {
104 | if (self.config.pinchStartLen > 0) {
105 | e.scale = getLen(v) / self.config.pinchStartLen
106 | self.config.pinch(e)
107 | }
108 | e.angle = getRotateAngle(v, preV)
109 | self.config.rotate(e)
110 | }
111 | preV.x = v.x
112 | preV.y = v.y
113 | } else {
114 | if (self.config.x2 !== null) {
115 | e.deltaX = currentX - self.config.x2
116 | e.deltaY = currentY - self.config.y2
117 | } else {
118 | e.deltaX = 0
119 | e.deltaY = 0
120 | }
121 | self.config.pressMove(e)
122 | }
123 | self.config.touchMove(e)
124 | self._cancelLongTap()
125 | self.config.x2 = currentX
126 | self.config.y2 = currentY
127 | if (e.touches.length > 1) {
128 | self._cancelLongTap()
129 | e.preventDefault()
130 | }
131 | }
132 | self.end = function (e) {
133 | if (!e.touches) return
134 | e.preventDefault()
135 | self._cancelLongTap()
136 | if (e.touches.length < 2) {
137 | self.config.multipointEnd(e)
138 | }
139 | self.config.touchEnd(e)
140 | // swipe
141 | if ((self.config.x2 && Math.abs(self.config.x1 - self.config.x2) > 30) ||
142 | (self.config.y2 && Math.abs(self.config.preV.y - self.config.y2) > 30)) {
143 | e.direction = self._swipeDirection(self.config.x1, self.config.x2, self.config.y1, self.config.y2)
144 | self.config.swipeTimeout = setTimeout(function () {
145 | self.config.swipe(e)
146 | }, 0)
147 | } else {
148 | self.config.tapTimeout = setTimeout(function () {
149 | self.config.tap(e)
150 | // trigger double tap immediately
151 | if (self.config.isDoubleTap) {
152 | self.config.doubleTap(e)
153 | clearTimeout(self.config.touchTimeout)
154 | self.config.isDoubleTap = false
155 | } else {
156 | self.config.touchTimeout = setTimeout(function () {
157 | self.config.singleTap(e)
158 | }, 250)
159 | }
160 | }, 0)
161 | }
162 | self.config.preV.x = 0
163 | self.config.preV.y = 0
164 | self.config.scale = 1
165 | self.config.pinchStartLen = null
166 | self.config.x1 = self.config.x2 = self.config.y1 = self.config.y2 = null
167 | }
168 | self.cancel = function (e) {
169 | clearTimeout(self.config.touchTimeout)
170 | clearTimeout(self.config.tapTimeout)
171 | clearTimeout(self.config.longTapTimeout)
172 | clearTimeout(self.config.swipeTimeout)
173 | self.config.touchCancel(e)
174 | }
175 | self._cancelLongTap = function (e) {
176 | clearTimeout(self.config.longTapTimeout)
177 | }
178 | self._swipeDirection = function (x1, x2, y1, y2) {
179 | return Math.abs(x1 - x2) >= Math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down')
180 | }
181 | // 自定义指令
182 | Vue.directive('tap', {
183 | bind (el, binding, vnode, oldVnode) {
184 | var args = binding.value.arg || {}
185 | args.el = el
186 | self.config.tap = function (e) {
187 | binding.value.methods.call(binding.value.methods, e, args)
188 | }
189 | el.addEventListener('touchstart', self.start, false)
190 | el.addEventListener('touchmove', self.move, false)
191 | el.addEventListener('touchend', self.end, false)
192 | el.addEventListener('touchcancel', self.cancel, false)
193 | }
194 | })
195 | Vue.directive('singleTap', {
196 | bind (el, binding, vnode, oldVnode) {
197 | var args = binding.value.arg || {}
198 | args.el = el
199 | self.config.singleTap = function (e) {
200 | binding.value.methods.call(binding.value.methods, e, args)
201 | }
202 | el.addEventListener('touchstart', self.start, false)
203 | el.addEventListener('touchmove', self.move, false)
204 | el.addEventListener('touchend', self.end, false)
205 | el.addEventListener('touchcancel', self.cancel, false)
206 | }
207 | })
208 | Vue.directive('longTap', {
209 | bind (el, binding, vnode, oldVnode) {
210 | var args = binding.value.arg || {}
211 | args.el = el
212 | self.config.longTap = function (e) {
213 | binding.value.methods.call(binding.value.methods, e, args)
214 | }
215 | el.addEventListener('touchstart', self.start, false)
216 | el.addEventListener('touchmove', self.move, false)
217 | el.addEventListener('touchend', self.end, false)
218 | el.addEventListener('touchcancel', self.cancel, false)
219 | }
220 | })
221 | Vue.directive('doubleTap', {
222 | bind (el, binding, vnode, oldVnode) {
223 | var args = binding.value.arg || {}
224 | args.el = el
225 | self.config.doubleTap = function (e) {
226 | binding.value.methods.call(binding.value.methods, e, args)
227 | }
228 | el.addEventListener('touchstart', self.start, false)
229 | el.addEventListener('touchmove', self.move, false)
230 | el.addEventListener('touchend', self.end, false)
231 | el.addEventListener('touchcancel', self.cancel, false)
232 | }
233 | })
234 | Vue.directive('pressMove', {
235 | bind (el, binding, vnode, oldVnode) {
236 | var args = binding.value.arg || {}
237 | args.el = el
238 | self.config.pressMove = function (e) {
239 | binding.value.methods.call(binding.value.methods, e, args)
240 | }
241 | el.addEventListener('touchstart', self.start, false)
242 | el.addEventListener('touchmove', self.move, false)
243 | el.addEventListener('touchend', self.end, false)
244 | el.addEventListener('touchcancel', self.cancel, false)
245 | }
246 | })
247 | Vue.directive('multipointStart', {
248 | bind (el, binding, vnode, oldVnode) {
249 | var args = binding.value.arg || {}
250 | args.el = el
251 | self.config.multipointStart = function (e) {
252 | binding.value.methods.call(binding.value.methods, e, args)
253 | }
254 | el.addEventListener('touchstart', self.start, false)
255 | el.addEventListener('touchmove', self.move, false)
256 | el.addEventListener('touchend', self.end, false)
257 | el.addEventListener('touchcancel', self.cancel, false)
258 | }
259 | })
260 | Vue.directive('multipointEnd', {
261 | bind (el, binding, vnode, oldVnode) {
262 | var args = binding.value.arg || {}
263 | args.el = el
264 | self.config.multipointEnd = function (e) {
265 | binding.value.methods.call(binding.value.methods, e, args)
266 | }
267 | el.addEventListener('touchstart', self.start, false)
268 | el.addEventListener('touchmove', self.move, false)
269 | el.addEventListener('touchend', self.end, false)
270 | el.addEventListener('touchcancel', self.cancel, false)
271 | }
272 | })
273 | Vue.directive('swipe', {
274 | bind (el, binding, vnode, oldVnode) {
275 | var args = binding.value.arg || {}
276 | args.el = el
277 | self.config.swipe = function (e) {
278 | binding.value.methods.call(binding.value.methods, e, args)
279 | }
280 | el.addEventListener('touchstart', self.start, false)
281 | el.addEventListener('touchmove', self.move, false)
282 | el.addEventListener('touchend', self.end, false)
283 | el.addEventListener('touchcancel', self.cancel, false)
284 | }
285 | })
286 | Vue.directive('pinch', {
287 | bind (el, binding, vnode, oldVnode) {
288 | var args = binding.value.arg || {}
289 | args.el = el
290 | self.config.pinch = function (e) {
291 | binding.value.methods.call(binding.value.methods, e, args)
292 | }
293 | el.addEventListener('touchstart', self.start, false)
294 | el.addEventListener('touchmove', self.move, false)
295 | el.addEventListener('touchend', self.end, false)
296 | el.addEventListener('touchcancel', self.cancel, false)
297 | }
298 | })
299 | Vue.directive('rotate', {
300 | bind (el, binding, vnode, oldVnode) {
301 | var args = binding.value.arg || {}
302 | args.el = el
303 | self.config.pinch = function (e) {
304 | binding.value.methods.call(binding.value.methods, e, args)
305 | }
306 | el.addEventListener('touchstart', self.start, false)
307 | el.addEventListener('touchmove', self.move, false)
308 | el.addEventListener('touchend', self.end, false)
309 | el.addEventListener('touchcancel', self.cancel, false)
310 | }
311 | })
312 | }
313 | export default vueFinger
314 |
--------------------------------------------------------------------------------