├── 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 | 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 | --------------------------------------------------------------------------------