vue-scroll
Version:
scroll directive for vuejs 2.0
203 lines (197 loc) • 5.84 kB
JavaScript
/**
* vue-scroll vundefined
* (c) 2019 Wang Pin
* @license MIT
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = global || self, global.VueScroll = factory());
}(this, (function () { 'use strict';
var debounce = function (func, delay) {
var inDebounce;
return function() {
var context = this;
var args = arguments;
clearTimeout(inDebounce);
inDebounce = setTimeout(function () { return func.apply(context, args); }, delay);
}
};
var throttle = function (func, limit) {
var lastFunc;
var lastRan;
return function() {
var context = this;
var args = arguments;
if (!lastRan) {
func.apply(context, args);
lastRan = Date.now();
} else {
clearTimeout(lastFunc);
lastFunc = setTimeout(function() {
if (Date.now() - lastRan >= limit) {
func.apply(context, args);
lastRan = Date.now();
}
}, limit - (Date.now() - lastRan));
}
}
};
var isNumber = function(arg) {
return typeof arg === 'number' && arg !== NaN
};
var isFunction = function(arg) {
return typeof arg === 'function'
};
var isObject = function(arg) {
return Object.prototype.toString.call(arg) === '[object Object]'
};
var isInteger = function(arg) {
return isNumber(arg) && Math.round(arg) === arg
};
var get = function(arg, path, def) {
try {
return eval(("arg." + path))
} catch (err) {
return def
}
};
var dom = (function () {
var listeners = new Map();
var SCROLL = 'scroll';
function addEventListener (element, event, funcs, opt) {
function fn (e) {
var data;
var target = e.target || e.srcElement;
e = e || window.e;
if (e.type === SCROLL) {
if (target === document) {
data = { scrollTop: get(document, 'body.scrollTop', 0), scrollLeft: get(document, 'body.scrollLeft', 0) };
} else {
data = { scrollTop: get(target, 'scrollTop', 0), scrollLeft: get(target, 'scrollLeft', 0) };
}
}
funcs.forEach(function (f) {
f(e, data);
});
}
if (isObject(opt)) {
if (isInteger(opt.throttle) && isFinite(opt.throttle) && opt.throttle > -1) {
fn = throttle(fn, opt.throttle);
}
if (isInteger(opt.debounce) && isFinite(opt.debounce) && opt.debounce > -1) {
fn = debounce(fn, opt.debounce);
}
}
if (event === SCROLL) {
if(element === document.body || element === document || element === window) {
document.onscroll = fn;
} else {
if (element.addEventListener) {
element.addEventListener(event, fn);
} else {
element.attachEvent('on' + event, fn);
}
}
}
}
function bind (element, event, fn, opt) {
var funcs, eventFuncs;
if (!isFunction(fn)) {
throw new Error('Scroll handler is not a function');
}
if (!listeners.has(element)) {
listeners.set(element, new Map());
}
funcs = listeners.get(element);
if (!funcs.has(event)) {
funcs.set(event, []);
}
eventFuncs = funcs.get(event);
if (!eventFuncs.length) {
addEventListener(element, event, eventFuncs, opt);
}
eventFuncs.push(fn);
}
function unbind (element, event, fn) {
var funcs, eventFuncs;
if (!isFunction(fn)) {
return;
}
if (!listeners.has(element)) {
listeners.set(element, new Map());
}
funcs = listeners.get(element);
if (!funcs.has(event)) {
funcs.set(event, []);
}
eventFuncs = funcs.get(event);
if (eventFuncs.indexOf(fn) > -1) {
eventFuncs.splice(eventFuncs.indexOf(fn), 1);
return true;
}
return false;
}
return {
bind: bind,
unbind: unbind
}
})();
var vuescroll = new Object;
vuescroll.install = function (Vue, options) {
options = options || {};
var SCROLL = 'scroll';
var THROTTLE = 'throttle';
var DEBOUNCE = 'debounce';
var VALID_ARGS = [THROTTLE, DEBOUNCE];
function bindValue (el, value, arg) {
var fn, opt = Object.assign({}, options);
if (isObject(value) || isFunction(value)) {
fn = value;
if (VALID_ARGS.indexOf(arg) > -1) {
fn = value.fn;
if (arg === THROTTLE) {
opt = { throttle: value.throttle};
} else if(arg === DEBOUNCE) {
opt = { debounce: value.debounce};
}
}
try {
dom.bind(el, SCROLL, fn, opt);
} catch(err) {
console.warn('Unexpected error happened when binding listener');
}
} else {
console.warn('Unexpected scroll properties');
}
}
function unbindValue (el, value, arg) {
var fn;
if (isObject(value) || isFunction(value)) {
fn = value;
if (VALID_ARGS.indexOf(arg) > -1) {
fn = value.fn;
}
dom.unbind(el, SCROLL, fn);
}
}
Vue.directive(SCROLL, {
bind: function(el, binding, vnode, oldVnode) {
bindValue(el, binding.value, binding.arg);
},
inserted: function(el, binding) {
},
update: function(el, binding) {
if (binding.value === binding.oldValue) {
return;
}
bindValue(el, binding.value, binding.arg);
unbindValue(el, binding.oldValue, binding.arg);
},
unbind: function(el, binding) {
unbindValue(el, binding.value, binding.arg);
}
});
};
return vuescroll;
})));