├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── index.d.ts ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .idea/ 3 | test/ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea 2 | test -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Jerry Bendy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-touch-events [![](https://img.shields.io/npm/v/vue2-touch-events.svg)](https://www.npmjs.com/package/vue2-touch-events) 2 | 3 | Enable tap / swipe / touch hold events for vue.js 2.x 4 | 5 | Features: 6 | 7 | * Common touch events, such as `tap`, `swipe`, `touchhold` ([more](#Bindings)) 8 | * All events support mouse and touch screen at same time 9 | * Optimized touch effects with `touchClass` option and `v-touch-class` directive 10 | * Binding multiple touch events on one DOM element 11 | * Customizable events with native-likely events handler 12 | * Allow splitting configurations for different DOM elements by `v-touch-options` directive 13 | * Directive names can be customized to avoid namespace conflict 14 | 15 | **This is for **vue.js 2.x** only. For vue.js 3.x see [this library](https://github.com/robinrodricks/vue3-touch-events).** 16 | 17 | ## Install 18 | 19 | To install with npm or yarn, use 20 | 21 | ```shell 22 | npm i -S vue2-touch-events 23 | 24 | // or 25 | 26 | yarn add vue2-touch-events 27 | ``` 28 | 29 | ## Usage 30 | 31 | ```js 32 | import Vue from 'vue' 33 | import Vue2TouchEvents from 'vue2-touch-events' 34 | 35 | Vue.use(Vue2TouchEvents) 36 | ``` 37 | 38 | In your `.vue` file: 39 | 40 | ```html 41 | 42 | Tap Me 43 | 44 | 45 | Tap Me 46 | 47 | 48 | Swipe Here 49 | 50 | 51 | Swipe Here 52 | 53 | 54 | Long Tap Event 55 | 56 | 57 | Down,start/Up,end Event 58 | 59 | 60 | Triggered once when starting to move and tapTolerance is exceeded 61 | Continuously triggering Event 62 | 63 | 64 | Touch and hold on the screen for a while 65 | 66 | 67 | Mix Multiple Events 73 | 74 | 75 | Different options 77 | 78 | 79 | Customize touch class 80 | 81 | Customize touch class 82 | 83 | 84 | Change namespace to 'kiss' 85 | ``` 86 | 87 | If you use vue and this plugin in UMD way (in a script tag) , this plugin is auto used. So it's not necessary to write `Vue.use(Vue2TouchEvents)`. 88 | 89 | ```html 90 | 91 | 92 | ``` 93 | 94 | ## APIs 95 | 96 | ### Global configuration (optional) 97 | 98 | ```js 99 | Vue.use(Vue2TouchEvents, { 100 | disableClick: false, 101 | touchClass: '', 102 | tapTolerance: 10, 103 | touchHoldTolerance: 400, 104 | swipeTolerance: 30, 105 | longTapTimeInterval: 400, 106 | namespace: 'touch' 107 | }) 108 | ``` 109 | 110 | * `disableClick` default `false`. Use touch event only, will not trigger click event. 111 | 112 | You should keep this value default if you use your website on both mobile and PC. 113 | 114 | If your website uses on mobile only, it's a good choice to set this value to `true` to get a better user experience, and it can resolve some touch pass-through issue. 115 | 116 | * `touchClass` default: `''`. Add an extra CSS class when touch start, and remove it when touch end. 117 | 118 | This is a global config, and you can use `v-touch-class` directive to overwrite this setting in a single component. 119 | 120 | * `tapTolerance` default `10`. The tolerance to ensure whether the tap event effective or not. 121 | 122 | * `touchHoldTolerance` default `400` in millisecond. The timeout for a `touchhold` event. 123 | 124 | * `swipeTolerance` default `30`. The tolerance to ensure whether the swipe event effective or not. 125 | 126 | * `longTapTimeInterval` default `400` in millisecond. The minimum time interval to detect whether long tap event effective or not. 127 | 128 | * `namespace` default `touch`(v3.2.0). Customize the directive names to avoid namespace conflict. By default, the `touch` means `v-touch` and `v-touch-class` are available, and you can use `v-click` and `v-click-class` by change `namespace` to `click`. 129 | 130 | ### Directives 131 | 132 | #### v-touch 133 | 134 | Bind the `v-touch` directive to components which you want to enable touch events. 135 | 136 | `v-touch` accepts an argument to tell it which event you want to bind. 137 | 138 | ```html 139 | Tap 140 | ``` 141 | 142 | The first argument of the `v-swipe` callback is the direction of swipe event. It could be `left`, `right`, `top` or `bottom`. 143 | 144 | `v-swipe` can accept extra modifiers. It means you can bind events only for specify direction. 145 | 146 | ```js 147 | export default { 148 | methods: { 149 | swipeHandler (direction) { 150 | console.log(direction) // May be left / right / top / bottom 151 | } 152 | } 153 | } 154 | ``` 155 | 156 | ### v-touch-options `(v2.2.0)` 157 | 158 | `v-touch-options` directive allows you set a different configuration for a specified component. It will override global configurations. 159 | 160 | #### v-touch-class 161 | 162 | `v-touch-class` directive allows you set an extra class on your components. If you already have a global config `touchClass`, this value will **overwrite** it. 163 | 164 | For example: 165 | 166 | ```html 167 | Tap Me 168 | ``` 169 | 170 | Now, when you start to touch, it will add an extra `active` class automatically. And remove it when touch end. 171 | 172 | If your setting of `disableClick` is `false` (it's default), it will bind `mouseenter` and `mouseleave` events, too. 173 | 174 | So that you can use this feature to instead of `:active` and `:hover` pseudo class, for a better user experience. 175 | 176 | ```css 177 | /* before */ 178 | span:active, span:hover { 179 | background: green; 180 | } 181 | 182 | /* now, you can write like this */ 183 | span.active { 184 | background: green; 185 | } 186 | ``` 187 | 188 | ### Bindings 189 | 190 | #### v-touch:tap / v-touch 191 | 192 | `tap` is the default event type of `v-touch`. It will be trigger when tap on the screen or click the mouse. 193 | 194 | #### v-touch:swipe 195 | 196 | `swipe` means touch on the screen and move in a direction. The direction could be `top`,`bottom`,`left` or `right`. 197 | 198 | #### v-touch:longtap 199 | 200 | > `longtap` will be deprecated in next major version. Please use `touchhold` insead. If you still want to use this feature, please let me know. 201 | 202 | `longtap` means touch on the screen and hold for a while. It will be triggered when you release your finger. (It's not normal when we use touch devices, so it's a good choice to use `touchhold` instaed) 203 | 204 | #### v-touch:touchhold `(v2.1.0)` 205 | 206 | `touchhold` will be triggered when touch on the screen and hold for `touchHoldTolerance` milliseconds. This will be triggered before your finger released, as what native APP does. 207 | 208 | #### v-touch:start / v-touch:end / v-touch:moving 209 | 210 | * `start` is same as `touchstart` or `mousedown`. 211 | * `end` is same as `touchend` or `mouseup`. 212 | * `moving` is same as `touchmovoe` or `mousemove`. 213 | 214 | These three events are like native DOM events. You can use these events to custom behaviors which this library doesn't support yet. 215 | 216 | ### Modifiers 217 | 218 | #### left, right, top, bottom 219 | 220 | This four modifiers are for `v-touch:swipe` only, to specify which direction you want to bind events to. 221 | 222 | #### self 223 | 224 | Same as `v-on:click.self`, only trigger events when the event target is the `currentTarget`. 225 | 226 | #### stop 227 | 228 | Same as `v-on:click.stop`, stops event propagation. 229 | 230 | #### prevent 231 | 232 | Same as `v-on:click.prevent`, prevents default event handler from firing. 233 | 234 | #### disablePassive `(v2.3.0)` 235 | 236 | `{passive: true}` is set for touch event listeners if your browser supports `passive`. This is good for user experience. If this is not what you want, you can use `disablePassive` modifier to prevent this behavior. 237 | 238 | ## Others 239 | 240 | ### How to add extra parameters 241 | 242 | As mentioned by [#3](https://github.com/jerrybendy/vue-touch-events/issues/3), if you want to add extra 243 | parameters for `v-touch`, you can't do that like `v-on`. The hack is that you can let your method returns 244 | a `function` and handle the extra parameters in the returned function. 245 | 246 | ```html 247 |
Swipe
248 | ``` 249 | 250 | ```js 251 | export default { 252 | methods: { 253 | myMethod (param) { 254 | return function(direction, event) { 255 | console.log(direction, param); 256 | // do something ~ 257 | } 258 | } 259 | } 260 | } 261 | ``` 262 | 263 | ### How to resolve conflict with vuetify 264 | Upgrade to the latest version (>= v3.2.0), and use the `namespace` parameter. For example: 265 | 266 | ```js 267 | import Vue2TouchEvents from 'vue2-touch-events' 268 | 269 | Vue.use(Vue2TouchEvents, { 270 | namespace: 'my-touch' 271 | }) 272 | ``` 273 | 274 | ## Change History 275 | 276 | [Look at here](https://github.com/jerrybendy/vue-touch-events/releases) 277 | 278 | ## LICENSE 279 | 280 | MIT License 281 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | import {PluginObject} from "vue"; 2 | 3 | declare const Vue2TouchEvents: PluginObject; 4 | 5 | export interface Vue2TouchEventsOptions { 6 | disableClick?: boolean; 7 | touchClass?: string; 8 | tapTolerance?: number; 9 | swipeTolerance?: number; 10 | longTapTimeInterval?: number; 11 | touchHoldTolerance?: number; 12 | namespace?: string; 13 | } 14 | 15 | export default Vue2TouchEvents; 16 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @author Jerry Bendy 4 | * @since 4/12/2017 5 | */ 6 | 7 | function touchX(event) { 8 | if(event.type.indexOf('mouse') !== -1){ 9 | return event.clientX; 10 | } 11 | return event.touches[0].clientX; 12 | } 13 | 14 | function touchY(event) { 15 | if(event.type.indexOf('mouse') !== -1){ 16 | return event.clientY; 17 | } 18 | return event.touches[0].clientY; 19 | } 20 | 21 | var isPassiveSupported = (function() { 22 | var supportsPassive = false; 23 | try { 24 | var opts = Object.defineProperty({}, 'passive', { 25 | get: function() { 26 | supportsPassive = true; 27 | } 28 | }); 29 | window.addEventListener('test', null, opts); 30 | } catch (e) {} 31 | return supportsPassive; 32 | })(); 33 | 34 | // Save last touch time globally (touch start time or touch end time), if a `click` event triggered, 35 | // and the time near by the last touch time, this `click` event will be ignored. This is used for 36 | // resolve touch through issue. 37 | var globalLastTouchTime = 0; 38 | 39 | var vueTouchEvents = { 40 | install: function (Vue, constructorOptions) { 41 | 42 | var globalOptions = Object.assign({}, { 43 | disableClick: false, 44 | tapTolerance: 10, // px 45 | swipeTolerance: 30, // px 46 | touchHoldTolerance: 400, // ms 47 | longTapTimeInterval: 400, // ms 48 | touchClass: '', 49 | namespace: 'touch' 50 | }, constructorOptions); 51 | 52 | function touchStartEvent(event) { 53 | var $this = this.$$touchObj, 54 | isTouchEvent = event.type.indexOf('touch') >= 0, 55 | isMouseEvent = event.type.indexOf('mouse') >= 0, 56 | $el = this; 57 | 58 | if (isTouchEvent) { 59 | globalLastTouchTime = event.timeStamp; 60 | } 61 | 62 | if (isMouseEvent && globalLastTouchTime && event.timeStamp - globalLastTouchTime < 350) { 63 | return; 64 | } 65 | 66 | if ($this.touchStarted) { 67 | return; 68 | } 69 | 70 | addTouchClass(this); 71 | 72 | $this.touchStarted = true; 73 | 74 | $this.touchMoved = false; 75 | $this.swipeOutBounded = false; 76 | 77 | $this.startX = touchX(event); 78 | $this.startY = touchY(event); 79 | 80 | $this.currentX = 0; 81 | $this.currentY = 0; 82 | 83 | $this.touchStartTime = event.timeStamp; 84 | 85 | // Trigger touchhold event after `touchHoldTolerance`ms 86 | $this.touchHoldTimer = setTimeout(function() { 87 | $this.touchHoldTimer = null; 88 | triggerEvent(event, $el, 'touchhold'); 89 | }, $this.options.touchHoldTolerance); 90 | 91 | triggerEvent(event, this, 'start'); 92 | } 93 | 94 | function touchMoveEvent(event) { 95 | var $this = this.$$touchObj; 96 | 97 | $this.currentX = touchX(event); 98 | $this.currentY = touchY(event); 99 | 100 | if (!$this.touchMoved) { 101 | var tapTolerance = $this.options.tapTolerance; 102 | 103 | $this.touchMoved = Math.abs($this.startX - $this.currentX) > tapTolerance || 104 | Math.abs($this.startY - $this.currentY) > tapTolerance; 105 | 106 | if($this.touchMoved){ 107 | cancelTouchHoldTimer($this); 108 | triggerEvent(event, this, 'moved'); 109 | } 110 | 111 | } else if (!$this.swipeOutBounded) { 112 | var swipeOutBounded = $this.options.swipeTolerance; 113 | 114 | $this.swipeOutBounded = Math.abs($this.startX - $this.currentX) > swipeOutBounded && 115 | Math.abs($this.startY - $this.currentY) > swipeOutBounded; 116 | } 117 | 118 | if($this.touchMoved){ 119 | triggerEvent(event, this, 'moving'); 120 | } 121 | } 122 | 123 | function touchCancelEvent() { 124 | var $this = this.$$touchObj; 125 | 126 | cancelTouchHoldTimer($this); 127 | removeTouchClass(this); 128 | 129 | $this.touchStarted = $this.touchMoved = false; 130 | $this.startX = $this.startY = 0; 131 | } 132 | 133 | function touchEndEvent(event) { 134 | var $this = this.$$touchObj, 135 | isTouchEvent = event.type.indexOf('touch') >= 0, 136 | isMouseEvent = event.type.indexOf('mouse') >= 0; 137 | 138 | if (isTouchEvent) { 139 | globalLastTouchTime = event.timeStamp; 140 | } 141 | 142 | var touchholdEnd = isTouchEvent && !$this.touchHoldTimer; 143 | cancelTouchHoldTimer($this); 144 | 145 | $this.touchStarted = false; 146 | 147 | removeTouchClass(this); 148 | 149 | if (isMouseEvent && globalLastTouchTime && event.timeStamp - globalLastTouchTime < 350) { 150 | return; 151 | } 152 | 153 | // Fix #33, Trigger `end` event when touch stopped 154 | triggerEvent(event, this, 'end'); 155 | 156 | if (!$this.touchMoved) { 157 | // detect if this is a longTap event or not 158 | if ($this.callbacks.longtap && event.timeStamp - $this.touchStartTime > $this.options.longTapTimeInterval) { 159 | if (event.cancelable) { 160 | event.preventDefault(); 161 | } 162 | triggerEvent(event, this, 'longtap'); 163 | 164 | } else if ($this.callbacks.touchhold && touchholdEnd) { 165 | if (event.cancelable) { 166 | event.preventDefault(); 167 | } 168 | return; 169 | } else { 170 | // emit tap event 171 | triggerEvent(event, this, 'tap'); 172 | } 173 | 174 | } else if (!$this.swipeOutBounded) { 175 | var swipeOutBounded = $this.options.swipeTolerance, 176 | direction, 177 | distanceY = Math.abs($this.startY - $this.currentY), 178 | distanceX = Math.abs($this.startX - $this.currentX); 179 | 180 | if (distanceY > swipeOutBounded || distanceX > swipeOutBounded) { 181 | if (distanceY > distanceX) { 182 | direction = $this.startY > $this.currentY ? 'top' : 'bottom'; 183 | } else { 184 | direction = $this.startX > $this.currentX ? 'left' : 'right'; 185 | } 186 | 187 | // Only emit the specified event when it has modifiers 188 | if ($this.callbacks['swipe.' + direction]) { 189 | triggerEvent(event, this, 'swipe.' + direction, direction); 190 | } else { 191 | // Emit a common event when it has no any modifier 192 | triggerEvent(event, this, 'swipe', direction); 193 | } 194 | } 195 | } 196 | } 197 | 198 | function mouseEnterEvent() { 199 | addTouchClass(this); 200 | } 201 | 202 | function mouseLeaveEvent() { 203 | removeTouchClass(this); 204 | } 205 | 206 | function triggerEvent(e, $el, eventType, param) { 207 | var $this = $el.$$touchObj; 208 | 209 | // get the callback list 210 | var callbacks = $this && $this.callbacks[eventType] || []; 211 | if (callbacks.length === 0) { 212 | return null; 213 | } 214 | 215 | for (var i = 0; i < callbacks.length; i++) { 216 | var binding = callbacks[i]; 217 | 218 | if (binding.modifiers.stop) { 219 | e.stopPropagation(); 220 | } 221 | 222 | if (binding.modifiers.prevent && e.cancelable) { 223 | e.preventDefault(); 224 | } 225 | 226 | // handle `self` modifier` 227 | if (binding.modifiers.self && e.target !== e.currentTarget) { 228 | continue; 229 | } 230 | 231 | if (typeof binding.value === 'function') { 232 | if (param) { 233 | binding.value(param, e); 234 | } else { 235 | binding.value(e); 236 | } 237 | } 238 | } 239 | } 240 | 241 | function addTouchClass($el) { 242 | var className = $el.$$touchObj.options.touchClass; 243 | className && $el.classList.add(className); 244 | } 245 | 246 | function removeTouchClass($el) { 247 | var className = $el.$$touchObj.options.touchClass; 248 | className && $el.classList.remove(className); 249 | } 250 | 251 | function cancelTouchHoldTimer($this) { 252 | if ($this.touchHoldTimer) { 253 | clearTimeout($this.touchHoldTimer); 254 | $this.touchHoldTimer = null; 255 | } 256 | } 257 | 258 | function buildTouchObj($el, extraOptions) { 259 | var touchObj = $el.$$touchObj || { 260 | // an object contains all callbacks registered, 261 | // key is event name, value is an array 262 | callbacks: {}, 263 | // prevent bind twice, set to true when event bound 264 | hasBindTouchEvents: false, 265 | // default options, would be override by v-touch-options 266 | options: globalOptions 267 | }; 268 | if (extraOptions) { 269 | touchObj.options = Object.assign({}, touchObj.options, extraOptions); 270 | } 271 | $el.$$touchObj = touchObj; 272 | return $el.$$touchObj; 273 | } 274 | 275 | Vue.directive(globalOptions.namespace, { 276 | bind: function ($el, binding) { 277 | // build a touch configuration object 278 | var $this = buildTouchObj($el); 279 | // declare passive option for the event listener. Defaults to { passive: true } if supported 280 | var passiveOpt = isPassiveSupported ? { passive: true } : false; 281 | // register callback 282 | var eventType = binding.arg || 'tap'; 283 | switch (eventType) { 284 | case 'swipe': 285 | var _m = binding.modifiers; 286 | if (_m.left || _m.right || _m.top || _m.bottom) { 287 | for (var i in binding.modifiers) { 288 | if (['left', 'right', 'top', 'bottom'].indexOf(i) >= 0) { 289 | var _e = 'swipe.' + i; 290 | $this.callbacks[_e] = $this.callbacks[_e] || []; 291 | $this.callbacks[_e].push(binding); 292 | } 293 | } 294 | } else { 295 | $this.callbacks.swipe = $this.callbacks.swipe || []; 296 | $this.callbacks.swipe.push(binding); 297 | } 298 | break; 299 | 300 | case 'start': 301 | case 'moving': 302 | if (binding.modifiers.disablePassive) { 303 | // change the passive option for the moving event if disablePassive modifier exists 304 | passiveOpt = false; 305 | } 306 | // fallthrough 307 | default: 308 | $this.callbacks[eventType] = $this.callbacks[eventType] || []; 309 | $this.callbacks[eventType].push(binding); 310 | } 311 | 312 | // prevent bind twice 313 | if ($this.hasBindTouchEvents) { 314 | return; 315 | } 316 | 317 | $el.addEventListener('touchstart', touchStartEvent, passiveOpt); 318 | $el.addEventListener('touchmove', touchMoveEvent, passiveOpt); 319 | $el.addEventListener('touchcancel', touchCancelEvent); 320 | $el.addEventListener('touchend', touchEndEvent); 321 | 322 | if (!$this.options.disableClick) { 323 | $el.addEventListener('mousedown', touchStartEvent); 324 | $el.addEventListener('mousemove', touchMoveEvent); 325 | $el.addEventListener('mouseup', touchEndEvent); 326 | $el.addEventListener('mouseenter', mouseEnterEvent); 327 | $el.addEventListener('mouseleave', mouseLeaveEvent); 328 | } 329 | 330 | // set bind mark to true 331 | $this.hasBindTouchEvents = true; 332 | }, 333 | 334 | unbind: function ($el) { 335 | $el.removeEventListener('touchstart', touchStartEvent); 336 | $el.removeEventListener('touchmove', touchMoveEvent); 337 | $el.removeEventListener('touchcancel', touchCancelEvent); 338 | $el.removeEventListener('touchend', touchEndEvent); 339 | 340 | if ($el.$$touchObj && !$el.$$touchObj.options.disableClick) { 341 | $el.removeEventListener('mousedown', touchStartEvent); 342 | $el.removeEventListener('mousemove', touchMoveEvent); 343 | $el.removeEventListener('mouseup', touchEndEvent); 344 | $el.removeEventListener('mouseenter', mouseEnterEvent); 345 | $el.removeEventListener('mouseleave', mouseLeaveEvent); 346 | } 347 | 348 | // remove vars 349 | delete $el.$$touchObj; 350 | } 351 | }); 352 | 353 | Vue.directive(globalOptions.namespace + '-class', { 354 | bind: function ($el, binding) { 355 | buildTouchObj($el, { 356 | touchClass: binding.value 357 | }); 358 | } 359 | }); 360 | 361 | Vue.directive(globalOptions.namespace + '-options', { 362 | bind: function($el, binding) { 363 | buildTouchObj($el, binding.value); 364 | } 365 | }); 366 | } 367 | }; 368 | 369 | 370 | /* 371 | * Exports 372 | */ 373 | if (typeof module === 'object') { 374 | module.exports = vueTouchEvents; 375 | 376 | } else if (typeof define === 'function' && define.amd) { 377 | define([], function () { 378 | return vueTouchEvents; 379 | }); 380 | } else if (window.Vue) { 381 | window.vueTouchEvents = vueTouchEvents; 382 | Vue.use(vueTouchEvents); 383 | } 384 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue2-touch-events", 3 | "version": "3.2.3", 4 | "description": "Simple touch events support for vueJS2", 5 | "main": "index.js", 6 | "types": "index.d.ts", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/jerrybendy/vue-touch-events.git" 13 | }, 14 | "keywords": [ 15 | "vue", 16 | "touch", 17 | "tap", 18 | "swipe", 19 | "longtap" 20 | ], 21 | "author": "Jerry Bendy ", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/jerrybendy/vue-touch-events/issues" 25 | }, 26 | "homepage": "https://github.com/jerrybendy/vue-touch-events#readme", 27 | "devDependencies": { 28 | "@types/vue": "^2.0.0" 29 | } 30 | } 31 | --------------------------------------------------------------------------------