我已经创建了一个JavaScript插件,我想有可能多次使用它,但是,如果将其称为页面两次,就像下面一样,它似乎不会创建一个新实例:< / p>
var lightbox = new MarvLightbox({
imagesContainer: 'detail-hdr__detail-images',
limit: 11
});
var lightbox2 = new MarvLightbox({
imagesContainer: 'image-grid-2',
galleryFolder: 2,
mobileFolder: 0
});
以下代码似乎返回相同的值,因此,例如,如果我单击图像以在c
对象中设置state
值,那么它的实例已更改{ {1}}和lightbox2
。
lightbox
我试图从我的插件中删除任何不需要的代码。但我基本上做的是: 1.编译容器中的图像列表。 2.从JSON字符串生成HTML。 3.将点击事件分配给图像,然后单击它们时打开灯箱并更改图像等。
MarvLightbox.prototype.current = function() {
console.log(state);
};
正如我上面所说,虽然(function() {
var instance = null,
container;
// Constructor
this.MarvLightbox = function() {
instance = this;
// Create global variables
this.images_count = -1;
this.active = false;
this.error = false;
this.debug = false;
// Define option defaults
var defaults = {
activeClass: 'marvLightbox',
appendTo: '#wrapper',
imagesContainer: null,
thumbClass: null,
lightboxId: 'marvLightbox',
galleryFolder: null,
mobileFolder: null,
showAlt: true,
showMax: true,
limit: null,
html: '{ "div": { "id": "{lightboxId}", "0": { "div": { "class": "{lightboxId}__container", "data-click": "EventClose", "0": { "div": { "class": "{lightboxId}__controls {lightboxId}__controls--top", "0": { "div": { "class": "{lightboxId}__eschint", "content": "Press <span>ESC</span> to close" } }, "1": { "div": { "class": "{lightboxId}__close", "data-click": "EventClose" } } } }, "1": { "div": { "class": "{lightboxId}__image", "0": { "img": { "src": "", "class": "responsive-img image", "data-click": "EventRight" } } } }, "2": { "div": { "class": "{lightboxId}__controls {lightboxId}__controls--bottom", "3": { "div": { "class": "{lightboxId}__left", "data-click": "EventLeft", "data-hover": "EventClass(#{lightboxId}, toggle: left)" } }, "4": { "div": { "class": "{lightboxId}__right", "data-click": "EventRight", "data-hover": "EventClass(#{lightboxId}, toggle: right)" } }, "5": { "div": { "class": "{lightboxId}__alt" } }, "6": { "div": { "class": "{lightboxId}__num" } } } } } } } }'
};
// Create options by extending defaults with the passed in arugments
if (arguments[0] && typeof arguments[0] === "object") {
this.options = extendDefaults(defaults, arguments[0]);
}
this.options.html = this.options.html.replace(/\{(lightboxId)}/g, this.options.lightboxId);
// this.options.limit = this.options.limit + 1;
// Check if debugging is enabled
(function() {
var args = document.querySelectorAll('[data-external-arg]');
if(args.length > 0 && args[0].src.indexOf('marv.lightbox') !== -1) {
if (args[0].dataset.externalArg === 'debug') instance.debug = true;
}
}());
// Initialise plugin
this.init();
};
// Debugging messages
var debug = function(code, arg) {
var args = function(n) {
if (arg === undefined) {
return '[arg undefined]';
}
if (arg[n] === undefined) {
return '[arg undefined]';
} else {
return arg[n];
}
};
var messages = function(code, argument) {
return [
'marv.lightbox(debug): Debugging mode is on, make sure you turn this off before you launch',
'marv.lightbox(debug): HTMLElement(' + args(0) + ') with the name of ' + args(1) + ' has been detected',
'marv.lightbox(debug): Found '+ arg + ' image/s within your Lightbox container ',
'marv.lightbox(debug): ' + args(0) + ' key pressed, changing current (' + args(1) + '), number of images (' + args(2) + ')',
'marv.lightbox(debug): Current is set to null, closing lightbox',
'marv.lightbox(debug): Inserting Lightbox within HTMLElement(' + args(1) + '), using ' + args(0),
'marv.lightbox(debug): 1 image found, don\'t add previous/next arrows, don\'t show numbers either',
'marv.lightbox(debug): showAlt set to false, don\'t display alt text',
'marv.lightbox(debug): showMax set to false, don\'t display numbers below alt text',
'marv.lightbox(debug): Reverting to mobile version (' + instance.options.mobileFolder + ') of images',
'marv.lightbox(debug): Over-riding to ' + instance.options.galleryFolder + ' version of images'
][code];
};
if (instance.debug === true)
console.log(messages(code, arg));
};
// Error messages
var error = function(code, arg) {
var args = function(n) {
if (arg === undefined) {
return '[arg undefined]';
}
if (arg[n] === undefined) {
return '[arg undefined]';
} else {
return arg[n];
}
};
var messages = function(code, argument) {
return [
'marv.lightbox(error): I need to know which images to use... add { imagesContainer: "id/class" } to the plugin initialization',
'marv.lightbox(error): The HTML structure provided appears to have an error: ' + arg,
'marv.lightbox(error): Issue compiling list of images, speak to Dev, error: ' + arg,
'marv.lightbox(error): Your going to need some images for this to work... make sure they have the class: ' + instance.options.thumbClass,
'marv.lightbox(error): I was unable to find an element which matches ' + instance.options.imagesContainer + ', please double check this',
'marv.lightbox(error): I was unable to find a container with the name of ' + args[0],
'marv.lightbox(error): EventListener with arguments passed, had an issue seperating arguments, check formatting',
'marv.lightbox(error): Unable to apply class event to element, please check your attribute',
'marv.lightbox(error): You have attempted to over-ride the images folder with a size that doesn\'t exist, please choose a size between 0 and ' + arg
][code];
};
console.log(messages(code, arg));
};
var imageSizes = function(e) {
var sizes = [ '344x258', 'full', 'large1' ];
if (sizes[e] !== undefined) {
return sizes[e];
}
error(8, sizes.length);
};
// Initilise the plugin
MarvLightbox.prototype.init = function() {
if (this.options.imagesContainer === null) {
error(0);
return;
}
container = (instance.options.imagesContainer).objectType();
if (container === null || container === undefined) {
error(4);
return;
}
debug(0);
setupLightbox();
};
// Generate HTML from JSON
function buildHTML(json) {
"use strict";
var handleAttribute = function(element, attribute, value) {
if (value instanceof HTMLElement) {
return element.appendChild(value);
}
switch (attribute) {
case 'class':
case 'src':
case 'id':
case 'data-click':
case 'data-hover':
return element.setAttribute(attribute, value);
case 'content':
element.innerHTML = value;
return;
// other keys...
default:
console.log(element.tagName, attribute, value);
}
};
var htmlReviver = function(key, value) {
// parse as element
if (isNaN(key) && typeof value === 'object') {
var element = document.createElement(key);
var subValue;
for (var attribute in value) {
handleAttribute(element, attribute, value[attribute]);
}
return element;
// move element from { index: { tagName: Element } } to { index: Element }
} else if (!isNaN(key)) {
return value[Object.keys(value)[0]];
// leave property alone
} else {
return value;
}
};
try {
var htmlObject = JSON.parse(json, htmlReviver);
return htmlObject;
} catch (e) {
error(1, e);
}
}
// Manage item change
var images_compiled;
var state = {
c: null,
altValue: null,
maxValue: null,
get current() { return this.c; },
get max() { return this.maxValue; },
get alt() { return this.altValue; },
set max(e) { this.maxValue = e; },
set alt(e) { this.altValue = e; },
set current(e) {
if (this.c !== null) {
// Remove class from current
(images_compiled[this.c].target).classList.remove('expand');
}
if (e === null) {
debug(4);
// Collapse Lightbox
if (document.getElementById(instance.options.lightboxId)) {
(images_compiled[this.c].target).classList.remove('expand');
document.getElementsByTagName('body')[0].classList.remove(instance.options.activeClass);
(document.getElementById(instance.options.lightboxId).parentNode).removeChild(document.getElementById(instance.options.lightboxId));
}
this.c = e;
return;
}
// Change current element, update lightbox
this.c = e;
var lightbox = document.getElementById(instance.options.lightboxId),
res;
// Check lightbox exists, if so change the image src
if (lightbox) {
var image = images_compiled[e].image.src;
if (instance.options.galleryFolder !== null) {
var filter = image.match(/([^\/]*)/g).filter(Boolean);
image = image.replace(filter[filter.length - 2], imageSizes(instance.options.galleryFolder));
}
lightbox.getElementsByTagName('img')[0].src = image;
if (instance.options.showAlt) {
debug(7);
lightbox.getElementsByClassName(instance.options.lightboxId + '__alt')[0].innerHTML = images_compiled[e].alt;
}
if (instance.options.showMax && this.max > 1) {
debug(8);
lightbox.getElementsByClassName(instance.options.lightboxId + '__num')[0].innerHTML = (images_compiled[e].index + 1) + '/' + this.max;
}
} else {
res = generateExpand(images_compiled[e]);
}
// Add active class
if (res) {
(images_compiled[e].target).classList.add('expand');
document.getElementsByTagName('body')[0].classList.add(instance.options.lightboxId);
}
}
};
// Setup light box
function setupLightbox() {
var images;
images = container.getElementsByTagName('img');
if (instance.options.limit !== null) {
var tmp = [];
for (var i = 0, length = images.length; i < length; i++) {
if (i < instance.options.limit) {
tmp.push(images[i]);
}
}
images = tmp;
}
if (images.length < 1 || images === undefined) {
error(3);
return;
}
try {
images_compiled = Array.from(images, function(el) {
// Generate array of objects containing image information
instance.images_count++;
return {
target: function() {
if (el.parentElement.nodeName === 'A') {
return el.parentElement;
}
return el;
}(),
index: instance.images_count,
alt: ((el.alt) ? el.alt : ''),
image: function() {
// If class put on an A link then find the image
if (el.tagName === 'A') {
return el.getElementsByTagName('img')[0];
} else {
return el;
}
}()
};
});
} catch(e) {
// Issue with generating array
error(2, e);
}
debug(2, images_compiled.length);
// Add image click event
images_compiled.forEach(function(el) {
if (el !== null) {
var elm = el.target;
elm.addEventListener('click', function(e) {
if (elm.nodeName === 'A') {
e.preventDefault();
}
instance.active = true;
if (state.current === el.index) {
state.current = null;
return;
}
state.current = el.index;
state.alt = el.alt;
});
}
});
state.max = images_compiled.length;
}
function generateExpand(img) {
// Generate lightbox HTML and append
var html = buildHTML(instance.options.html);
instance.events = {
EventClose: function(evt) {
if (evt !== undefined) {
evt.stopPropagation();
}
instance.active = false;
state.current = null;
},
EventLeft: function(evt) {
if (evt !== undefined) {
evt.stopPropagation();
}
if (state.current !== 0 && state.max > 1) {
state.current = state.current - 1;
} else {
state.current = instance.images_count;
}
},
EventRight: function(evt) {
if (evt !== undefined) {
evt.stopPropagation();
}
if (state.current !== instance.images_count && state.max > 1) {
state.current = state.current + 1;
} else {
state.current = 0;
}
},
EventClass: function(evt) {
var arg = (evt.dataset.hover).replace(/ /g,''),
args = (arg.match(/[^(]*/g).filter(Boolean))[1].match(/(?:([^,()]+)?)+/g).filter(Boolean),
target = args[0].objectType(),
action = args[1].match(/^(.*):(.*)/).filter(Boolean);
switch(action[1]) {
case 'add':
// Add class
target.classList.add(action[2]);
break;
case 'remove':
// Remove class
target.classList.remove(action[2]);
break;
case 'toggle':
target.classList.add(action[2]);
evt.addEventListener('mouseout', function() {
target.classList.remove(action[2]);
});
break;
default:
// Error
error(7);
break;
}
}
};
// Lightbox is active
instance.active = true;
// Assign event listeners
Array.prototype.forEach.call(html.querySelectorAll('[data-click]'), function (e) {
e.addEventListener('click', instance.events[eventName(e.dataset.click)]);
});
Array.prototype.forEach.call(html.querySelectorAll('[data-hover]'), function (e) {
e.addEventListener('mouseover', function() { instance.events[eventName(e.dataset.hover)](e); });
});
// Insert lightbox into website
var appendTo = (instance.options.appendTo).objectType();
if (appendTo === null || (instance.options.appendTo).objectType() === undefined) {
error(5, [instance.options.appendTo]);
return false;
}
debug(5, ['id', instance.options.imagesContainer]);
appendTo.insertBefore(html, appendTo.firstChild);
return true;
}
MarvLightbox.prototype.current = function() {
console.log(state);
};
}());
对象似乎在两个实例之间共享,但它应该是唯一的。
答案 0 :(得分:0)
问题在于实例我认为:
var instance = null;
MarvLightbox = function() {
instance = this;
因此,无论何时创建新的Lightbox,实例都会指向它。这也适用于异步回调函数,它们都指向最后一个而不是当前实例。您可以在本地范围实例:
var instance=this;
同样适用于州:
MarvLightbox.prototype.current = function() {
console.log(this.state); //make it an objects property, not global
};