vue-observe-visibility
Advanced tools
Comparing version 0.3.1 to 0.4.0
@@ -1,39 +0,316 @@ | ||
function throwValueError(value) { | ||
if (value !== null && typeof value !== 'function') { | ||
throw new Error('observe-visibility directive expects a function as the value'); | ||
var asyncGenerator = function () { | ||
function AwaitValue(value) { | ||
this.value = value; | ||
} | ||
function AsyncGenerator(gen) { | ||
var front, back; | ||
function send(key, arg) { | ||
return new Promise(function (resolve, reject) { | ||
var request = { | ||
key: key, | ||
arg: arg, | ||
resolve: resolve, | ||
reject: reject, | ||
next: null | ||
}; | ||
if (back) { | ||
back = back.next = request; | ||
} else { | ||
front = back = request; | ||
resume(key, arg); | ||
} | ||
}); | ||
} | ||
function resume(key, arg) { | ||
try { | ||
var result = gen[key](arg); | ||
var value = result.value; | ||
if (value instanceof AwaitValue) { | ||
Promise.resolve(value.value).then(function (arg) { | ||
resume("next", arg); | ||
}, function (arg) { | ||
resume("throw", arg); | ||
}); | ||
} else { | ||
settle(result.done ? "return" : "normal", result.value); | ||
} | ||
} catch (err) { | ||
settle("throw", err); | ||
} | ||
} | ||
function settle(type, value) { | ||
switch (type) { | ||
case "return": | ||
front.resolve({ | ||
value: value, | ||
done: true | ||
}); | ||
break; | ||
case "throw": | ||
front.reject(value); | ||
break; | ||
default: | ||
front.resolve({ | ||
value: value, | ||
done: false | ||
}); | ||
break; | ||
} | ||
front = front.next; | ||
if (front) { | ||
resume(front.key, front.arg); | ||
} else { | ||
back = null; | ||
} | ||
} | ||
this._invoke = send; | ||
if (typeof gen.return !== "function") { | ||
this.return = undefined; | ||
} | ||
} | ||
if (typeof Symbol === "function" && Symbol.asyncIterator) { | ||
AsyncGenerator.prototype[Symbol.asyncIterator] = function () { | ||
return this; | ||
}; | ||
} | ||
AsyncGenerator.prototype.next = function (arg) { | ||
return this._invoke("next", arg); | ||
}; | ||
AsyncGenerator.prototype.throw = function (arg) { | ||
return this._invoke("throw", arg); | ||
}; | ||
AsyncGenerator.prototype.return = function (arg) { | ||
return this._invoke("return", arg); | ||
}; | ||
return { | ||
wrap: function (fn) { | ||
return function () { | ||
return new AsyncGenerator(fn.apply(this, arguments)); | ||
}; | ||
}, | ||
await: function (value) { | ||
return new AwaitValue(value); | ||
} | ||
}; | ||
}(); | ||
var classCallCheck = function (instance, Constructor) { | ||
if (!(instance instanceof Constructor)) { | ||
throw new TypeError("Cannot call a class as a function"); | ||
} | ||
}; | ||
var createClass = function () { | ||
function defineProperties(target, props) { | ||
for (var i = 0; i < props.length; i++) { | ||
var descriptor = props[i]; | ||
descriptor.enumerable = descriptor.enumerable || false; | ||
descriptor.configurable = true; | ||
if ("value" in descriptor) descriptor.writable = true; | ||
Object.defineProperty(target, descriptor.key, descriptor); | ||
} | ||
} | ||
return function (Constructor, protoProps, staticProps) { | ||
if (protoProps) defineProperties(Constructor.prototype, protoProps); | ||
if (staticProps) defineProperties(Constructor, staticProps); | ||
return Constructor; | ||
}; | ||
}(); | ||
var toConsumableArray = function (arr) { | ||
if (Array.isArray(arr)) { | ||
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; | ||
return arr2; | ||
} else { | ||
return Array.from(arr); | ||
} | ||
}; | ||
function processOptions(value) { | ||
var options = void 0; | ||
if (typeof value === 'function') { | ||
// Simple options (callback-only) | ||
options = { | ||
callback: value | ||
}; | ||
} else { | ||
// Options object | ||
options = value; | ||
} | ||
return options; | ||
} | ||
var ObserveVisibility = { | ||
bind: function bind(el, _ref, vnode) { | ||
var value = _ref.value; | ||
function throttle(callback, delay) { | ||
var timeout = void 0; | ||
var lastState = void 0; | ||
var currentArgs = void 0; | ||
var throttled = function throttled(state) { | ||
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | ||
args[_key - 1] = arguments[_key]; | ||
} | ||
if (typeof IntersectionObserver === 'undefined') { | ||
console.warn('[vue-observe-visibility] IntersectionObserver API is not available in your browser. Please install this polyfill: https://github.com/WICG/IntersectionObserver/tree/gh-pages/polyfill'); | ||
} else { | ||
throwValueError(value); | ||
el._vue_visibilityCallback = value; | ||
var observer = el._vue_intersectionObserver = new IntersectionObserver(function (entries) { | ||
currentArgs = args; | ||
if (timeout && state === lastState) return; | ||
lastState = state; | ||
clearTimeout(timeout); | ||
timeout = setTimeout(function () { | ||
callback.apply(undefined, [state].concat(toConsumableArray(currentArgs))); | ||
timeout = 0; | ||
}, delay); | ||
}; | ||
throttled._clear = function () { | ||
clearTimeout(timeout); | ||
}; | ||
return throttled; | ||
} | ||
var VisibilityState = function () { | ||
function VisibilityState(el, options, vnode) { | ||
classCallCheck(this, VisibilityState); | ||
this.el = el; | ||
this.observer = null; | ||
this.createObserver(options, vnode); | ||
} | ||
createClass(VisibilityState, [{ | ||
key: 'createObserver', | ||
value: function createObserver(options, vnode) { | ||
var _this = this; | ||
if (this.observer) { | ||
this.destroyObserver(); | ||
} | ||
this.options = processOptions(options); | ||
this.callback = this.options.callback; | ||
// Throttle | ||
if (this.callback && this.options.throttle) { | ||
this.callback = throttle(this.callback, this.options.throttle); | ||
} | ||
this.observer = new IntersectionObserver(function (entries) { | ||
var entry = entries[0]; | ||
if (el._vue_visibilityCallback) { | ||
el._vue_visibilityCallback.call(null, entry.intersectionRatio > 0, entry); | ||
if (_this.callback) { | ||
// Use isIntersecting if possible because browsers can report isIntersecting as true, but intersectionRatio as 0, when something very slowly enters the viewport. | ||
_this.callback(entry.isIntersecting && entry.intersectionRatio >= _this.threshold, entry); | ||
} | ||
}); | ||
}, this.options.intersection); | ||
// Wait for the element to be in document | ||
vnode.context.$nextTick(function () { | ||
observer.observe(el); | ||
_this.observer.observe(_this.el); | ||
}); | ||
} | ||
}, { | ||
key: 'destroyObserver', | ||
value: function destroyObserver() { | ||
if (this.observer) { | ||
this.observer.disconnect(); | ||
} | ||
// Cancel throttled call | ||
if (this.callback && this.callback._clear) { | ||
this.callback._clear(); | ||
} | ||
} | ||
}, { | ||
key: 'threshold', | ||
get: function get$$1() { | ||
return this.options.intersection && this.options.intersection.threshold; | ||
} | ||
}]); | ||
return VisibilityState; | ||
}(); | ||
var ObserveVisibility = { | ||
bind: function bind(el, _ref, vnode) { | ||
var value = _ref.value; | ||
if (typeof IntersectionObserver === 'undefined') { | ||
console.warn('[vue-observe-visibility] IntersectionObserver API is not available in your browser. Please install this polyfill: https://github.com/w3c/IntersectionObserver/tree/master/polyfill'); | ||
} else { | ||
var state = new VisibilityState(el, value, vnode); | ||
el._vue_visibilityState = state; | ||
} | ||
}, | ||
update: function update(el, _ref2) { | ||
update: function update(el, _ref2, vnode) { | ||
var value = _ref2.value; | ||
throwValueError(value); | ||
el._vue_visibilityCallback = value; | ||
var state = el._vue_visibilityState; | ||
if (state) { | ||
state.createObserver(value, vnode); | ||
} else { | ||
this.bind(el, { value: value }, vnode); | ||
} | ||
}, | ||
unbind: function unbind(el) { | ||
if (el._vue_intersectionObserver) { | ||
el._vue_intersectionObserver.disconnect(); | ||
delete el._vue_intersectionObserver; | ||
delete el._vue_visibilityCallback; | ||
var state = el._vue_visibilityState; | ||
if (state) { | ||
state.destroyObserver(); | ||
delete el._vue_visibilityState; | ||
} | ||
@@ -55,3 +332,3 @@ } | ||
// eslint-disable-next-line no-undef | ||
version: "0.3.1", | ||
version: "0.4.0", | ||
install: install | ||
@@ -58,0 +335,0 @@ }; |
@@ -1,1 +0,1 @@ | ||
var VueObserveVisibility=function(e){"use strict";function i(e){if(null!==e&&"function"!=typeof e)throw new Error("observe-visibility directive expects a function as the value")}function t(e){e.directive("observe-visibility",n)}var n={bind:function(e,t,n){var l=t.value;if("undefined"==typeof IntersectionObserver)console.warn("[vue-observe-visibility] IntersectionObserver API is not available in your browser. Please install this polyfill: https://github.com/WICG/IntersectionObserver/tree/gh-pages/polyfill");else{i(l),e._vue_visibilityCallback=l;var r=e._vue_intersectionObserver=new IntersectionObserver(function(i){var t=i[0];e._vue_visibilityCallback&&e._vue_visibilityCallback.call(null,t.intersectionRatio>0,t)});n.context.$nextTick(function(){r.observe(e)})}},update:function(e,t){var n=t.value;i(n),e._vue_visibilityCallback=n},unbind:function(e){e._vue_intersectionObserver&&(e._vue_intersectionObserver.disconnect(),delete e._vue_intersectionObserver,delete e._vue_visibilityCallback)}},l={version:"0.3.1",install:t},r=null;return"undefined"!=typeof window?r=window.Vue:"undefined"!=typeof global&&(r=global.Vue),r&&r.use(l),e.install=t,e.ObserveVisibility=n,e.default=l,e}({}); | ||
var VueObserveVisibility=function(e){"use strict";function t(e){return"function"==typeof e?{callback:e}:e}function n(e,t){var n=void 0,r=void 0,i=void 0,o=function(o){for(var a=arguments.length,l=Array(a>1?a-1:0),c=1;c<a;c++)l[c-1]=arguments[c];i=l,n&&o===r||(r=o,clearTimeout(n),n=setTimeout(function(){e.apply(void 0,[o].concat(s(i))),n=0},t))};return o._clear=function(){clearTimeout(n)},o}function r(e){e.directive("observe-visibility",l)}!function(){function e(e){this.value=e}function t(t){function n(i,o){try{var s=t[i](o),a=s.value;a instanceof e?Promise.resolve(a.value).then(function(e){n("next",e)},function(e){n("throw",e)}):r(s.done?"return":"normal",s.value)}catch(e){r("throw",e)}}function r(e,t){switch(e){case"return":i.resolve({value:t,done:!0});break;case"throw":i.reject(t);break;default:i.resolve({value:t,done:!1})}(i=i.next)?n(i.key,i.arg):o=null}var i,o;this._invoke=function(e,t){return new Promise(function(r,s){var a={key:e,arg:t,resolve:r,reject:s,next:null};o?o=o.next=a:(i=o=a,n(e,t))})},"function"!=typeof t.return&&(this.return=void 0)}"function"==typeof Symbol&&Symbol.asyncIterator&&(t.prototype[Symbol.asyncIterator]=function(){return this}),t.prototype.next=function(e){return this._invoke("next",e)},t.prototype.throw=function(e){return this._invoke("throw",e)},t.prototype.return=function(e){return this._invoke("return",e)}}();var i=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},o=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),s=function(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t<e.length;t++)n[t]=e[t];return n}return Array.from(e)},a=function(){function e(t,n,r){i(this,e),this.el=t,this.observer=null,this.createObserver(n,r)}return o(e,[{key:"createObserver",value:function(e,r){var i=this;this.observer&&this.destroyObserver(),this.options=t(e),this.callback=this.options.callback,this.callback&&this.options.throttle&&(this.callback=n(this.callback,this.options.throttle)),this.observer=new IntersectionObserver(function(e){var t=e[0];i.callback&&i.callback(t.isIntersecting&&t.intersectionRatio>=i.threshold,t)},this.options.intersection),r.context.$nextTick(function(){i.observer.observe(i.el)})}},{key:"destroyObserver",value:function(){this.observer&&this.observer.disconnect(),this.callback&&this.callback._clear&&this.callback._clear()}},{key:"threshold",get:function(){return this.options.intersection&&this.options.intersection.threshold}}]),e}(),l={bind:function(e,t,n){var r=t.value;if("undefined"==typeof IntersectionObserver)console.warn("[vue-observe-visibility] IntersectionObserver API is not available in your browser. Please install this polyfill: https://github.com/w3c/IntersectionObserver/tree/master/polyfill");else{var i=new a(e,r,n);e._vue_visibilityState=i}},update:function(e,t,n){var r=t.value,i=e._vue_visibilityState;i?i.createObserver(r,n):this.bind(e,{value:r},n)},unbind:function(e){var t=e._vue_visibilityState;t&&(t.destroyObserver(),delete e._vue_visibilityState)}},c={version:"0.4.0",install:r},u=null;return"undefined"!=typeof window?u=window.Vue:"undefined"!=typeof global&&(u=global.Vue),u&&u.use(c),e.install=r,e.ObserveVisibility=l,e.default=c,e}({}); |
@@ -7,40 +7,317 @@ (function (global, factory) { | ||
function throwValueError(value) { | ||
if (value !== null && typeof value !== 'function') { | ||
throw new Error('observe-visibility directive expects a function as the value'); | ||
var asyncGenerator = function () { | ||
function AwaitValue(value) { | ||
this.value = value; | ||
} | ||
function AsyncGenerator(gen) { | ||
var front, back; | ||
function send(key, arg) { | ||
return new Promise(function (resolve, reject) { | ||
var request = { | ||
key: key, | ||
arg: arg, | ||
resolve: resolve, | ||
reject: reject, | ||
next: null | ||
}; | ||
if (back) { | ||
back = back.next = request; | ||
} else { | ||
front = back = request; | ||
resume(key, arg); | ||
} | ||
}); | ||
} | ||
function resume(key, arg) { | ||
try { | ||
var result = gen[key](arg); | ||
var value = result.value; | ||
if (value instanceof AwaitValue) { | ||
Promise.resolve(value.value).then(function (arg) { | ||
resume("next", arg); | ||
}, function (arg) { | ||
resume("throw", arg); | ||
}); | ||
} else { | ||
settle(result.done ? "return" : "normal", result.value); | ||
} | ||
} catch (err) { | ||
settle("throw", err); | ||
} | ||
} | ||
function settle(type, value) { | ||
switch (type) { | ||
case "return": | ||
front.resolve({ | ||
value: value, | ||
done: true | ||
}); | ||
break; | ||
case "throw": | ||
front.reject(value); | ||
break; | ||
default: | ||
front.resolve({ | ||
value: value, | ||
done: false | ||
}); | ||
break; | ||
} | ||
front = front.next; | ||
if (front) { | ||
resume(front.key, front.arg); | ||
} else { | ||
back = null; | ||
} | ||
} | ||
this._invoke = send; | ||
if (typeof gen.return !== "function") { | ||
this.return = undefined; | ||
} | ||
} | ||
if (typeof Symbol === "function" && Symbol.asyncIterator) { | ||
AsyncGenerator.prototype[Symbol.asyncIterator] = function () { | ||
return this; | ||
}; | ||
} | ||
AsyncGenerator.prototype.next = function (arg) { | ||
return this._invoke("next", arg); | ||
}; | ||
AsyncGenerator.prototype.throw = function (arg) { | ||
return this._invoke("throw", arg); | ||
}; | ||
AsyncGenerator.prototype.return = function (arg) { | ||
return this._invoke("return", arg); | ||
}; | ||
return { | ||
wrap: function (fn) { | ||
return function () { | ||
return new AsyncGenerator(fn.apply(this, arguments)); | ||
}; | ||
}, | ||
await: function (value) { | ||
return new AwaitValue(value); | ||
} | ||
}; | ||
}(); | ||
var classCallCheck = function (instance, Constructor) { | ||
if (!(instance instanceof Constructor)) { | ||
throw new TypeError("Cannot call a class as a function"); | ||
} | ||
}; | ||
var createClass = function () { | ||
function defineProperties(target, props) { | ||
for (var i = 0; i < props.length; i++) { | ||
var descriptor = props[i]; | ||
descriptor.enumerable = descriptor.enumerable || false; | ||
descriptor.configurable = true; | ||
if ("value" in descriptor) descriptor.writable = true; | ||
Object.defineProperty(target, descriptor.key, descriptor); | ||
} | ||
} | ||
return function (Constructor, protoProps, staticProps) { | ||
if (protoProps) defineProperties(Constructor.prototype, protoProps); | ||
if (staticProps) defineProperties(Constructor, staticProps); | ||
return Constructor; | ||
}; | ||
}(); | ||
var toConsumableArray = function (arr) { | ||
if (Array.isArray(arr)) { | ||
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; | ||
return arr2; | ||
} else { | ||
return Array.from(arr); | ||
} | ||
}; | ||
function processOptions(value) { | ||
var options = void 0; | ||
if (typeof value === 'function') { | ||
// Simple options (callback-only) | ||
options = { | ||
callback: value | ||
}; | ||
} else { | ||
// Options object | ||
options = value; | ||
} | ||
return options; | ||
} | ||
var ObserveVisibility = { | ||
bind: function bind(el, _ref, vnode) { | ||
var value = _ref.value; | ||
function throttle(callback, delay) { | ||
var timeout = void 0; | ||
var lastState = void 0; | ||
var currentArgs = void 0; | ||
var throttled = function throttled(state) { | ||
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | ||
args[_key - 1] = arguments[_key]; | ||
} | ||
if (typeof IntersectionObserver === 'undefined') { | ||
console.warn('[vue-observe-visibility] IntersectionObserver API is not available in your browser. Please install this polyfill: https://github.com/WICG/IntersectionObserver/tree/gh-pages/polyfill'); | ||
} else { | ||
throwValueError(value); | ||
el._vue_visibilityCallback = value; | ||
var observer = el._vue_intersectionObserver = new IntersectionObserver(function (entries) { | ||
currentArgs = args; | ||
if (timeout && state === lastState) return; | ||
lastState = state; | ||
clearTimeout(timeout); | ||
timeout = setTimeout(function () { | ||
callback.apply(undefined, [state].concat(toConsumableArray(currentArgs))); | ||
timeout = 0; | ||
}, delay); | ||
}; | ||
throttled._clear = function () { | ||
clearTimeout(timeout); | ||
}; | ||
return throttled; | ||
} | ||
var VisibilityState = function () { | ||
function VisibilityState(el, options, vnode) { | ||
classCallCheck(this, VisibilityState); | ||
this.el = el; | ||
this.observer = null; | ||
this.createObserver(options, vnode); | ||
} | ||
createClass(VisibilityState, [{ | ||
key: 'createObserver', | ||
value: function createObserver(options, vnode) { | ||
var _this = this; | ||
if (this.observer) { | ||
this.destroyObserver(); | ||
} | ||
this.options = processOptions(options); | ||
this.callback = this.options.callback; | ||
// Throttle | ||
if (this.callback && this.options.throttle) { | ||
this.callback = throttle(this.callback, this.options.throttle); | ||
} | ||
this.observer = new IntersectionObserver(function (entries) { | ||
var entry = entries[0]; | ||
if (el._vue_visibilityCallback) { | ||
el._vue_visibilityCallback.call(null, entry.intersectionRatio > 0, entry); | ||
if (_this.callback) { | ||
// Use isIntersecting if possible because browsers can report isIntersecting as true, but intersectionRatio as 0, when something very slowly enters the viewport. | ||
_this.callback(entry.isIntersecting && entry.intersectionRatio >= _this.threshold, entry); | ||
} | ||
}); | ||
}, this.options.intersection); | ||
// Wait for the element to be in document | ||
vnode.context.$nextTick(function () { | ||
observer.observe(el); | ||
_this.observer.observe(_this.el); | ||
}); | ||
} | ||
}, { | ||
key: 'destroyObserver', | ||
value: function destroyObserver() { | ||
if (this.observer) { | ||
this.observer.disconnect(); | ||
} | ||
// Cancel throttled call | ||
if (this.callback && this.callback._clear) { | ||
this.callback._clear(); | ||
} | ||
} | ||
}, { | ||
key: 'threshold', | ||
get: function get$$1() { | ||
return this.options.intersection && this.options.intersection.threshold; | ||
} | ||
}]); | ||
return VisibilityState; | ||
}(); | ||
var ObserveVisibility = { | ||
bind: function bind(el, _ref, vnode) { | ||
var value = _ref.value; | ||
if (typeof IntersectionObserver === 'undefined') { | ||
console.warn('[vue-observe-visibility] IntersectionObserver API is not available in your browser. Please install this polyfill: https://github.com/w3c/IntersectionObserver/tree/master/polyfill'); | ||
} else { | ||
var state = new VisibilityState(el, value, vnode); | ||
el._vue_visibilityState = state; | ||
} | ||
}, | ||
update: function update(el, _ref2) { | ||
update: function update(el, _ref2, vnode) { | ||
var value = _ref2.value; | ||
throwValueError(value); | ||
el._vue_visibilityCallback = value; | ||
var state = el._vue_visibilityState; | ||
if (state) { | ||
state.createObserver(value, vnode); | ||
} else { | ||
this.bind(el, { value: value }, vnode); | ||
} | ||
}, | ||
unbind: function unbind(el) { | ||
if (el._vue_intersectionObserver) { | ||
el._vue_intersectionObserver.disconnect(); | ||
delete el._vue_intersectionObserver; | ||
delete el._vue_visibilityCallback; | ||
var state = el._vue_visibilityState; | ||
if (state) { | ||
state.destroyObserver(); | ||
delete el._vue_visibilityState; | ||
} | ||
@@ -62,3 +339,3 @@ } | ||
// eslint-disable-next-line no-undef | ||
version: "0.3.1", | ||
version: "0.4.0", | ||
install: install | ||
@@ -65,0 +342,0 @@ }; |
{ | ||
"name": "vue-observe-visibility", | ||
"description": "Detect when an element is becoming visible or hidden on the page. ", | ||
"version": "0.3.1", | ||
"version": "0.4.0", | ||
"author": { | ||
@@ -23,8 +23,6 @@ "name": "Guillaume Chau", | ||
"build:umd": "rollup --config build/rollup.config.umd.js", | ||
"prepublish": "npm run build", | ||
"dev": "cross-env NODE_ENV=development rollup --config build/rollup.config.es.js --watch" | ||
"prepublishOnly": "npm run build", | ||
"dev": "nodemon --exec 'npm run build' --watch src", | ||
"serve": "serve --open ./dist" | ||
}, | ||
"watch": { | ||
"build": "src/*.js" | ||
}, | ||
"repository": { | ||
@@ -52,3 +50,3 @@ "type": "git", | ||
"eslint-plugin-standard": "^3.0.1", | ||
"npm-watch": "^0.2.0", | ||
"nodemon": "^1.17.5", | ||
"rollup": "^0.50.0", | ||
@@ -64,4 +62,5 @@ "rollup-plugin-babel": "^3.0.2", | ||
"rollup-plugin-vue": "^2.4.1", | ||
"serve": "^6.5.8", | ||
"uglify-es": "^3.0.28" | ||
} | ||
} |
@@ -22,5 +22,5 @@ # vue-observe-visibility | ||
**⚠️ This plugin uses the [Intersection Observer API](https://github.com/WICG/IntersectionObserver) that is not currently supported in every browser (Chrome does though). You need to include a [polyfill](https://github.com/WICG/IntersectionObserver/tree/gh-pages/polyfill) to make it work on the incompatible browsers.** | ||
**⚠️ This plugin uses the [Intersection Observer API](http://caniuse.com/#feat=intersectionobserver) that is not supported in every browser (currently supported in Edge, Firefox and Chrome). You need to include a [polyfill](https://github.com/w3c/IntersectionObserver/tree/master/polyfill) to make it work on incompatible browsers.** | ||
## Default import | ||
## Import | ||
@@ -66,6 +66,61 @@ ```javascript | ||
The `v-observe-visibility` directive is very easy to use: just pass a function as the value, which will be called whenever the visiblity of the element changes with the argument being a boolean (`true` means the element is visible on the page, `false` means that it is not). | ||
The `v-observe-visibility` directive is very easy to use. Just pass a function as the value: | ||
```html | ||
<div v-observe-visibility="visibilityChanged"> | ||
``` | ||
This also works on components: | ||
```html | ||
<MyComponent v-observe-visibility="visibilityChanged" /> | ||
``` | ||
The function will be called whenever the visiblity of the element changes with the argument being a boolean (`true` means the element is visible on the page, `false` means that it is not). | ||
The second argument is the corresponding [IntersectionObserverEntry](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry) object. | ||
```javascript | ||
visibilityChanged (isVisible, entry) { | ||
this.isVisible = isVisible | ||
console.log(entry) | ||
} | ||
``` | ||
## IntersectionObserver options | ||
It's possible to pass the [IntersectionObserver `options` object](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/IntersectionObserver#Parameters) using the `intersection` attribute: | ||
```html | ||
<div v-observe-visibility="{ | ||
callback: visibilityChanged, | ||
intersection: { | ||
root: ..., | ||
rootMargin: ..., | ||
threshold: 0.3, | ||
}, | ||
}"> | ||
``` | ||
## Throttling visibility | ||
You can use the `throttle` options (in ms) specifying minimal state duration after which an event will be fired. It's useful when you are tracking visibility while scrolling and don't want events from fastly scrolled out elements. | ||
```html | ||
<div v-observe-visibility="{ | ||
callback: visibilityChanged, | ||
throttle: 300, | ||
}"> | ||
``` | ||
## Passing custom arguments | ||
You can add custom argument by using an intermediate function: | ||
```html | ||
<div v-observe-visibility="(isVisible, entry) => visibilityChanged(isVisible, entry, customArgument)"> | ||
``` | ||
Here `visibilityChanged` will be call with a third custom argument `customArgument`. | ||
# Example | ||
@@ -87,10 +142,10 @@ | ||
show: true, | ||
isVisible: true | ||
isVisible: true, | ||
}, | ||
methods: { | ||
visibilityChanged: function (isVisible, entry) { | ||
visibilityChanged (isVisible, entry) { | ||
this.isVisible = isVisible | ||
console.log(entry) | ||
} | ||
} | ||
}, | ||
}, | ||
}) | ||
@@ -97,0 +152,0 @@ </script> |
@@ -1,5 +0,51 @@ | ||
function throwValueError (value) { | ||
if (value !== null && typeof value !== 'function') { | ||
throw new Error('observe-visibility directive expects a function as the value') | ||
import { processOptions, throttle } from '../utils' | ||
class VisibilityState { | ||
constructor (el, options, vnode) { | ||
this.el = el | ||
this.observer = null | ||
this.createObserver(options, vnode) | ||
} | ||
get threshold () { | ||
return this.options.intersection && this.options.intersection.threshold | ||
} | ||
createObserver (options, vnode) { | ||
if (this.observer) { | ||
this.destroyObserver() | ||
} | ||
this.options = processOptions(options) | ||
this.callback = this.options.callback | ||
// Throttle | ||
if (this.callback && this.options.throttle) { | ||
this.callback = throttle(this.callback, this.options.throttle) | ||
} | ||
this.observer = new IntersectionObserver(entries => { | ||
var entry = entries[0] | ||
if (this.callback) { | ||
// Use isIntersecting if possible because browsers can report isIntersecting as true, but intersectionRatio as 0, when something very slowly enters the viewport. | ||
this.callback(entry.isIntersecting && entry.intersectionRatio >= this.threshold, entry) | ||
} | ||
}, this.options.intersection) | ||
// Wait for the element to be in document | ||
vnode.context.$nextTick(() => { | ||
this.observer.observe(this.el) | ||
}) | ||
} | ||
destroyObserver () { | ||
if (this.observer) { | ||
this.observer.disconnect() | ||
} | ||
// Cancel throttled call | ||
if (this.callback && this.callback._clear) { | ||
this.callback._clear() | ||
} | ||
} | ||
} | ||
@@ -10,29 +56,25 @@ | ||
if (typeof IntersectionObserver === 'undefined') { | ||
console.warn('[vue-observe-visibility] IntersectionObserver API is not available in your browser. Please install this polyfill: https://github.com/WICG/IntersectionObserver/tree/gh-pages/polyfill') | ||
console.warn('[vue-observe-visibility] IntersectionObserver API is not available in your browser. Please install this polyfill: https://github.com/w3c/IntersectionObserver/tree/master/polyfill') | ||
} else { | ||
throwValueError(value) | ||
el._vue_visibilityCallback = value | ||
const observer = el._vue_intersectionObserver = new IntersectionObserver(entries => { | ||
var entry = entries[0] | ||
if (el._vue_visibilityCallback) { | ||
el._vue_visibilityCallback.call(null, entry.intersectionRatio > 0, entry) | ||
} | ||
}) | ||
// Wait for the element to be in document | ||
vnode.context.$nextTick(() => { | ||
observer.observe(el) | ||
}) | ||
const state = new VisibilityState(el, value, vnode) | ||
el._vue_visibilityState = state | ||
} | ||
}, | ||
update (el, { value }) { | ||
throwValueError(value) | ||
el._vue_visibilityCallback = value | ||
update (el, { value }, vnode) { | ||
const state = el._vue_visibilityState | ||
if (state) { | ||
state.createObserver(value, vnode) | ||
} else { | ||
this.bind(el, { value }, vnode) | ||
} | ||
}, | ||
unbind (el) { | ||
if (el._vue_intersectionObserver) { | ||
el._vue_intersectionObserver.disconnect() | ||
delete el._vue_intersectionObserver | ||
delete el._vue_visibilityCallback | ||
const state = el._vue_visibilityState | ||
if (state) { | ||
state.destroyObserver() | ||
delete el._vue_visibilityState | ||
} | ||
}, | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
214153
733
157
26
16
1