├── .babelrc ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── dist └── vue-throttle-event.js ├── package.json ├── src └── index.js ├── test └── test.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["latest"], 3 | "comments": false 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - lts/carbon 5 | 6 | install: 7 | - npm install 8 | 9 | script: 10 | - npm run start 11 | 12 | cache: 13 | directories: 14 | 15 | deploy: 16 | provider: npm 17 | email: marcoboffo.waves@gmail.com 18 | skip_cleanup: true 19 | api_key: 20 | secure: MCtAkHo0sDjKoTgt/NA4OHBq5o931IQ74jj836A3Q1MHYhaEVzRnRcI3+/GskZLFoXEHiMEIUX9lSPfq91kzsubwNws2q0DHtmbmLvIavmZCzMAe/LZRgr25uptXA/XN6J74xONNz3AEj0LNtwRKjdxaD6YG2M9sd8rNEoYL4vQFSDmG1F5mPAXBA3U/SAieu2z7ToTXtQo+ldO0yXQbH+1L1ovG0ptbtpOUcQzqKSTE/KS6N2p24IHddMC7QuUqaoJg7ew/plHLxFHm7FR1wdkO0p2rKCnDECgBMExyiKPvtFA+TZVc4r+YLegReJZDEG4SkSXmzD+lJhg3dA6MmAR1Pg/f18MxHixeNC8oRjka6BoLJz2pw+ZzGPAQUYczDByHhUex5VqLNCyYe6uUNPdFqaeT7IbTp1DBOaPuiYIDFljGufGljuzcncrlcvY45PNouAOHu9TYKEwBJinVfwyuu0X0nThwF+Bx4AwZfPQ3A+HL92yuzMtA3BE1OkiAhSc8APAuKQ/qSk5XvscRINGdxB72Uut0fNfU9ia3ZvO0890SWyVhjV0q3wx4S1Jmy0y/LMVRTSPx+FC5KBuBAIuAKIGWe9Jzo/qOA1OcR3SI0svfNzjdmiuMM8ttqfrGkil48fLTesIaapXif7DO2FmBCJVBp4udJvpzT3J3eTY= 21 | on: 22 | tags: true 23 | repo: scaccogatto/vue-throttle-event 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Marco 'Gatto' Boffo 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-throttle-event 2 | 3 | > throttle events based on requestAnimationFrame 4 | 5 | ## Status 6 | [![Build Status](https://travis-ci.org/scaccogatto/vue-throttle-event.svg?branch=master)](https://travis-ci.org/scaccogatto/vue-throttle-event) 7 | 8 | ## Features 9 | 10 | - Uses [requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) 11 | - Exposes an istance method called `$throttle` in every Vue Component 12 | - Fires a [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent) when ready 13 | 14 | ## Installation 15 | 16 | ### npm 17 | ``` 18 | $ npm install vue-throttle-event --save-dev 19 | ``` 20 | 21 | ### Vue's main.js 22 | ```js 23 | import VueThrottleEvent from 'vue-throttle-event' 24 | 25 | Vue.use(VueThrottleEvent) 26 | ``` 27 | 28 | ## Usage 29 | 30 | ### Example 31 | ```js 32 | methods: { 33 | customEventHandler (e) { 34 | // e.detail.origin is the original event object 35 | // logic here.. 36 | } 37 | } 38 | created () { 39 | this.$throttle('mousemove', 'mouse-moved-throttled') 40 | this.$on('mouse-moved-throttled', this.customEventHandler) 41 | } 42 | ``` 43 | 44 | ### Arguments 45 | - type (String): the event [type](https://developer.mozilla.org/en-US/docs/Web/Events) 46 | - customEventName (String): the custom event name that will be fired on next requestAnimationFrame 47 | - targetObject (Object) [optional]: the physical [EventTarget](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget) where the [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent) will be fired, defaults on [vm.$el](https://vuejs.org/v2/api/#vm-el) 48 | 49 | ### Returns 50 | - `function` representing the real function added to the `targetObject`, so you can unbind it when you want 51 | 52 | ## Testing 53 | This software uses [mocha](https://mochajs.org/) as testing framework 54 | 55 | - Clone this repository 56 | - `cd vue-throttle-event` 57 | - `npm install` 58 | - `npm test` 59 | 60 | *Feel free to contribute and ask questions* 61 | -------------------------------------------------------------------------------- /dist/vue-throttle-event.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.VueThrottleEvent=t():e.VueThrottleEvent=t()}(this,function(){return function(e){function t(o){if(n[o])return n[o].exports;var r=n[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,t),r.l=!0,r.exports}var n={};return t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,o){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:o})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=1)}([function(e,t){try{var n=new window.CustomEvent("test");if(n.preventDefault(),n.defaultPrevented!==!0)throw new Error("Could not prevent default")}catch(e){var o=function(e,t){var n,o;return t=t||{bubbles:!1,cancelable:!1,detail:void 0},n=document.createEvent("CustomEvent"),n.initCustomEvent(e,t.bubbles,t.cancelable,t.detail),o=n.preventDefault,n.preventDefault=function(){o.call(this);try{Object.defineProperty(this,"defaultPrevented",{get:function(){return!0}})}catch(e){this.defaultPrevented=!0}},n};o.prototype=window.Event.prototype,window.CustomEvent=o}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),n(0);var o={install:function(e){e.prototype.$throttle=o._throttle},_throttle:function(e,t,n){n=n||this.$el;var o=!1,r=function(e){o||(o=!0,window.requestAnimationFrame(function(){n.dispatchEvent(new window.CustomEvent(t,{detail:{origin:e}})),o=!1}))};return n.addEventListener(e,r),r}};t.default=o,"undefined"!=typeof window&&window.Vue&&window.Vue.use(o)}])}); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-throttle-event", 3 | "version": "1.5.0", 4 | "description": "throttle events based on requestAnimationFrame", 5 | "author": { 6 | "name": "Marco Boffo", 7 | "email": "marcoboffo.waves@gmail.com" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/scaccogatto/vue-throttle-event.git" 12 | }, 13 | "main": "dist/vue-throttle-event.js", 14 | "license": "MIT", 15 | "scripts": { 16 | "start": "webpack --config webpack.config.js", 17 | "test": "mocha" 18 | }, 19 | "dependencies": { 20 | "vue": "^2.0.1" 21 | }, 22 | "devDependencies": { 23 | "babel-core": "^6.18.2", 24 | "babel-loader": "^6.2.8", 25 | "babel-preset-latest": "^6.16.0", 26 | "custom-event-polyfill": "^0.3.0", 27 | "jsdom": "^9.8.3", 28 | "mocha": "^3.2.0", 29 | "mocha-jsdom": "^1.1.0", 30 | "webpack": "^2.1.0-beta.27" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import 'custom-event-polyfill' 2 | 3 | const VueThrottleEvent = { 4 | install (Vue) { 5 | // define the main instance function 6 | Vue.prototype.$throttle = VueThrottleEvent._throttle 7 | }, 8 | _throttle (type, name, obj) { 9 | obj = obj || this.$el 10 | let running = false 11 | 12 | // define the async function 13 | let func = (e) => { 14 | if (running) return 15 | 16 | // now is running 17 | running = true 18 | window.requestAnimationFrame(() => { 19 | obj.dispatchEvent(new window.CustomEvent(name, { detail: { origin: e } })) 20 | running = false 21 | }) 22 | } 23 | 24 | // define the classic event 25 | obj.addEventListener(type, func) 26 | 27 | // return it 28 | return func 29 | } 30 | } 31 | 32 | export default VueThrottleEvent 33 | 34 | // in-browser load 35 | if (typeof window !== 'undefined' && window.Vue) { 36 | window.Vue.use(VueThrottleEvent) 37 | } 38 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert') 2 | const jsdom = require('mocha-jsdom') 3 | 4 | const VueThrottleEvent = require('../dist/vue-throttle-event.js').default 5 | 6 | describe('VueThrottleEvent', () => { 7 | // DOM teardown 8 | jsdom() 9 | 10 | let Vue 11 | 12 | beforeEach (() => { 13 | Vue = { prototype: {} } 14 | }) 15 | 16 | describe('install', () => { 17 | it('should set the $throttle method correctly', () => { 18 | VueThrottleEvent.install(Vue) 19 | assert.equal(typeof Vue.prototype.$throttle, 'function') 20 | }) 21 | }) 22 | 23 | describe('_throttle', () => { 24 | it('should call a \'test-throttled-event\' on next animation frame', function(done) { 25 | // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ 26 | // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating 27 | 28 | // requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel 29 | 30 | // MIT license 31 | 32 | (function() { 33 | var lastTime = 0; 34 | var vendors = ['ms', 'moz', 'webkit', 'o']; 35 | for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { 36 | window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; 37 | window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] 38 | || window[vendors[x]+'CancelRequestAnimationFrame']; 39 | } 40 | 41 | if (!window.requestAnimationFrame) 42 | window.requestAnimationFrame = function(callback, element) { 43 | var currTime = new Date().getTime(); 44 | var timeToCall = Math.max(0, 16 - (currTime - lastTime)); 45 | var id = window.setTimeout(function() { callback(currTime + timeToCall); }, 46 | timeToCall); 47 | lastTime = currTime + timeToCall; 48 | return id; 49 | }; 50 | 51 | if (!window.cancelAnimationFrame) 52 | window.cancelAnimationFrame = function(id) { 53 | clearTimeout(id); 54 | }; 55 | }()); // TODO: move this in an external file, but actually i need it only here 56 | 57 | // set event listener 58 | window.addEventListener('test-throttled-event', () => { done() }) 59 | 60 | // set the throttled event 61 | VueThrottleEvent._throttle('test-event', 'test-throttled-event', window) 62 | 63 | // dispatch the normal event 64 | window.dispatchEvent(new window.CustomEvent('test-event')) 65 | window.requestAnimationFrame(() => {}) 66 | 67 | // it should be fired in 500ms or less 68 | this.timeout(500) 69 | }) 70 | 71 | it('should return a function', () => { 72 | // set the throttled event 73 | let func = VueThrottleEvent._throttle('test-event', 'test-throttled-event', window) 74 | assert.ok(typeof func === 'function') 75 | }) 76 | }) 77 | }) 78 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const path = require('path'); 3 | 4 | const config = { 5 | entry: './src/index.js', 6 | output: { 7 | path: path.resolve(__dirname, './dist'), 8 | filename: 'vue-throttle-event.js', 9 | library: 'VueThrottleEvent', 10 | libraryTarget: 'umd' 11 | }, 12 | module: { 13 | rules: [ 14 | { 15 | test: /\.js$/, 16 | include: path.resolve(__dirname, './src'), 17 | exclude: /node_modules/, 18 | use: "babel-loader" 19 | } 20 | ] 21 | }, 22 | plugins: [ 23 | new webpack.optimize.UglifyJsPlugin() 24 | ] 25 | } 26 | 27 | module.exports = config; 28 | --------------------------------------------------------------------------------