├── src ├── finger.js └── util.js ├── .gitignore ├── package.json ├── README.md └── index.js /src/finger.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | var hashGen = function(){ 2 | return Math.random().toString(36).substr(2, 5) 3 | } 4 | module.exports = { 5 | hashGen:hashGen 6 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-finger", 3 | "version": "0.1.0", 4 | "description": "Vue plugin for supporting touch gesture", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/Muxi-Studio/vue-finger.git" 12 | }, 13 | "keywords": [ 14 | "vuejs" 15 | ], 16 | "author": "Muxi FE Team", 17 | "license": "MIT", 18 | "bugs": { 19 | "url": "https://github.com/Muxi-Studio/vue-finger/issues" 20 | }, 21 | "homepage": "https://github.com/Muxi-Studio/vue-finger#readme" 22 | } 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-finger 2 | 3 | Vue plugin for supporting touch gesture. Support Vue 2.0+. 4 | 5 | Gesture supported: 6 | 7 | + Swipe 8 | + SwipeMove 9 | + Pinch 10 | + Tap 11 | + Double Tap 12 | 13 | 14 | ### Install 15 | 16 | ``` 17 | npm install vue-finger --save 18 | ``` 19 | 20 | ### Usage 21 | 22 | ``` 23 | import vueFinger from "vue-finger" 24 | 25 | Vue.use(vueFinger) 26 | 27 | ``` 28 | 29 | in your component 30 | 31 | ``` 32 | 37 | 38 | 39 | 48 | 49 | ``` 50 | 51 | 52 | ### Event 53 | 54 | #### Swipe 55 | 56 | `e.direction` 57 | 58 | the direction of the swipe: "Left", "Right", "Up", "Down". 59 | 60 | `e.deltaX` 61 | 62 | the delta on X axis of the whole swipe. 63 | 64 | `e.deltaY` 65 | 66 | the delta on Y axis of the whole swipe. 67 | 68 | #### SwipeMove 69 | 70 | `e.direction` 71 | 72 | the direction of the swipe: "Left", "Right", "Up", "Down". 73 | 74 | `e.distenceX` 75 | 76 | the cumulate distence on X axis of the swipe. 77 | 78 | `e.distenceY` 79 | 80 | the cumulate distence on Y axis of the swipe. 81 | 82 | #### Pinch 83 | 84 | `e.customScale` 85 | 86 | the difference value between latest scale and last scale 87 | 88 | #### Tap 89 | 90 | no custom event props 91 | 92 | #### doubleTap 93 | 94 | no custom event props 95 | 96 | 97 | ### Contributors 98 | 99 | + [zxc0328](https://github.com/zxc0328) 100 | + [Elegenthus](https://github.com/Elegenthus) 101 | 102 | ### Lisence 103 | 104 | DWTFYW 105 | 106 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var util = require("./src/util.js") 2 | 3 | var vueFingerConstructor = function(el, options) { 4 | this.el = el 5 | // add touch event 6 | this.startCallback = this.start.bind(this) 7 | this.moveCallback = this.move.bind(this) 8 | this.endCallback = this.end.bind(this) 9 | this.cancelCallback = this.cancel.bind(this) 10 | 11 | 12 | this.el.addEventListener("touchstart", this.startCallback, false) 13 | this.el.addEventListener("touchmove", this.moveCallback, false) 14 | this.el.addEventListener("touchend", this.endCallback, false) 15 | this.el.addEventListener("touchcancel", this.cancelCallback, false) 16 | 17 | // init 18 | this.x1 = this.x2 = this.y1 = this.y2 = null 19 | this.swipe = options.swipe 20 | this.swipeMove = options.swipeMove 21 | this.pintch = options.pintch 22 | this.tap = options.tap 23 | this.doubleTap = options.doubleTap 24 | this.pintchDistance = 400 25 | this.tapTimeout 26 | this.mutiTouchWating = true 27 | this.swipeMoveTimeout 28 | this.doubleTapTimeout 29 | // scale 30 | } 31 | 32 | vueFingerConstructor.prototype = { 33 | start: function(e) { 34 | var self = this 35 | console.log("start") 36 | // reset 37 | this.x1 = this.x2 = this.y1 = this.y2 = null 38 | 39 | e.preventDefault() 40 | if (!e.touches) return 41 | this.x1 = e.touches[0].pageX 42 | this.y1 = e.touches[0].pageY 43 | if(e.touches.length > 1){ 44 | this.mutiTouchWating = false 45 | this.p1 = e.touches[1].pageX 46 | this.q1 = e.touches[1].pageY 47 | this.pintchDistance1 = Math.sqrt(Math.pow((this.x1-this.p1),2) + Math.pow((this.y1-this.q1),2)) 48 | } 49 | 50 | this.previous = { 51 | x1: this.x1, 52 | y1: this.y1 53 | } 54 | e.distanceX = 0 55 | e.distanceY = 0 56 | 57 | // set tap timout 58 | if (this.tap) { 59 | if (e.target !== this.el) { 60 | this.tapTimeout = 61 | setTimeout(this.tap.bind({}, e, Array.prototype.slice.call(this.el.childNodes).indexOf(e.target)),200) 62 | }else { 63 | this.tapTimeout = setTimeout(function(){ 64 | if (!self.doubleTapTimeout) { 65 | console.log(self.tap) 66 | self.tap() 67 | } 68 | },200) 69 | } 70 | } 71 | 72 | this.mutiTouchWating = true 73 | setTimeout(function(){ 74 | self.mutiTouchWating = false 75 | },40) 76 | 77 | if (this.doubleTap && (e.touches.length == 1)) { 78 | if (this.doubleTapTimeout){ 79 | this.doubleTap() 80 | this.doubleTapTimeout = null 81 | }else{ 82 | this.doubleTapTimeout = setTimeout(function(){ 83 | this.doubleTapTimeout = null 84 | },100) 85 | } 86 | } 87 | }, 88 | move: function(e) { 89 | e.preventDefault() 90 | if (this.tapTimeout) { 91 | clearTimeout(this.tapTimeout) 92 | this.tapTimeout = null 93 | } 94 | if (this.doubleTapTimeout) { 95 | clearTimeout(this.doubleTapTimeout) 96 | this.doubleTapTimeout = null 97 | } 98 | 99 | var currentX = e.touches[0].pageX, 100 | currentY = e.touches[0].pageY; 101 | 102 | if(e.touches.length > 1){ 103 | var currentP = e.touches[1].pageX, 104 | currentQ = e.touches[1].pageY; 105 | this.p2 = currentP 106 | this.q2 = currentQ 107 | } 108 | 109 | this.x2 = currentX 110 | this.y2 = currentY 111 | 112 | e.distanceX = this.x2 - this.x1 113 | e.distanceY = this.y2 - this.y1 114 | if(e.touches.length > 1){ 115 | this.pintchDistance2 = Math.sqrt(Math.pow((this.x2 - this.p2),2) + Math.pow((this.y2 - this.q2),2)) 116 | //alert(this.pintchDistance2,this.pintchDistance1) 117 | e.customscale = (this.pintchDistance2 - this.pintchDistance1)/this.pintchDistance 118 | if (this.pintch) { 119 | this.pintch(e) 120 | } 121 | } 122 | 123 | 124 | 125 | e.deltaX = currentX - this.previous.x1 126 | e.deltaY = currentY - this.previous.y1 127 | 128 | this.previous = { 129 | x1: currentX, 130 | y1: currentY, 131 | p1: currentP, 132 | q1: currentQ 133 | } 134 | 135 | if ((currentX && Math.abs(e.distanceX) > 30) || 136 | (currentY && Math.abs(e.distanceY) > 30)) { 137 | e.direction = this._swipeDirection(this.x1, this.x2, this.y1, this.y2); 138 | if (this.swipeMove && (e.touches.length == 1) && !this.mutiTouchWating) this.swipeMove(e) 139 | } 140 | }, 141 | end: function(e) { 142 | 143 | 144 | e.preventDefault() 145 | if ((this.x2 && Math.abs(this.x1 - this.x2) > 30) || 146 | (this.y2 && Math.abs(this.y1 - this.y2) > 30)) { 147 | e.direction = this._swipeDirection(this.x1, this.x2, this.y1, this.y2); 148 | e.distanceX = this.x2 - this.x1 149 | e.distanceY = this.y2 - this.y1 150 | if (this.swipe) this.swipe(e) 151 | } 152 | }, 153 | cancel: function() { 154 | 155 | }, 156 | detach: function() { 157 | // remove touch event 158 | this.el.removeEventListener("touchstart", this.startCallback, false) 159 | this.el.removeEventListener("touchmove", this.moveCallback, false) 160 | this.el.removeEventListener("touchend", this.endCallback, false) 161 | this.el.removeEventListener("touchcancel", this.cancelCallback, false) 162 | }, 163 | _swipeDirection: function(x1, x2, y1, y2) { 164 | return Math.abs(x1 - x2) >= Math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down') 165 | } 166 | } 167 | 168 | var instancesHash = {} 169 | var vueFinger = {} 170 | 171 | vueFinger.install = function(Vue, options) { 172 | 173 | Vue.directive('finger', { 174 | bind: function(el, binding, vnode, oldVnode) { 175 | if (!el.dataset.vfingerId) { 176 | el.dataset.vfingerId = util.hashGen() 177 | var options = {} 178 | options[binding.arg] = binding.value 179 | var ins = new vueFingerConstructor(el, options) 180 | instancesHash[el.dataset.vfingerId] = ins 181 | }else { 182 | instancesHash[el.dataset.vfingerId][binding.arg] = binding.value 183 | } 184 | }, 185 | unbind: function(el) { 186 | var ins = instancesHash[el.dataset.vfingerId] 187 | ins.detach() 188 | ins = null 189 | } 190 | }) 191 | 192 | } 193 | 194 | module.exports = vueFinger 195 | --------------------------------------------------------------------------------