Элементы изотопа и javascript больше не могут быть изменены после добавления нового
Я пытаюсь сделать таблицу изображений, загруженных из json (а не реального json, больше похоже на массив javascript), и каждый раз, когда json изменяется (когда я добавляю новое изображение в json файл с некоторым скриптом, я хочу, чтобы моя таблица изображений для загрузки также.
Это формат json:
[{
"image": "images/set_1_UTC+03.jpg",
"weight": 101
}, {
"image": "images/set_1_UTC+03.jpg",
"weight": 102
}, {
"image": "images/set_1_UTC+03.jpg",
"weight": 103
}, {
"image": "images/set_1_UTC+03.jpg",
"weight": 104
}]
Для этого я использую изотоп. Мне удалось достичь всего, о чем я упоминал выше, единственная проблема заключается в том, что я хотел сделать клики интерактивными и всякий раз, когда я нажимаю одно изображение, чтобы иметь его в большем размере, и когда я нажимаю его снова, чтобы вернуться к небольшому размеру, Вот код:
<script>
var previous = 0;
var current = 0;
loadJSON(function(response) {
// Parse JSON string into object
current = JSON.parse(response);
});
function loadJSON(callback) {
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', 'data.json', true); // Replace 'my_data' with the path to your file
xobj.onreadystatechange = function() {
if (xobj.readyState == 4 && xobj.status == "200") {
// Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode
callback(xobj.responseText);
}
};
xobj.send(null);
}
let lengthOfprevious = previous.length;
setInterval(function() {
loadJSON(function(response) {
// Parse JSON string into object
current = JSON.parse(response);
});
previous = current;
if (lengthOfprevious != current.length) {
UpdateBody(lengthOfprevious);
}
lengthOfprevious = previous.length;
}, 5000);
function UpdateBody(startIndex) {
var newElements = "";
for (let i = startIndex; i < previous.length; i++) {
$(document).ready(function() {
newElements = "";
newElements +=
'<div class="photo element-item">' +
'<a href="' + previous[i].image + '"><img class="small-image" src="' + previous[i].image + '"/></a>' +
'<a class="weight">' + previous[i].weight + '</a></div>';
var $newElems = $(newElements);
$('#container').append($newElems).imagesLoaded(function() {
$('#container').isotope('insert', $newElems);
});
});
}
// ============//
$(function() {
var $container = $('#container'),
$photos = $container.find('.photo'),
$loadingIndicator = $('<div class="loading"><span><img src="http://i.imgur.com/IE7iw.gif" /></span></div>');
// trigger Isotope after images have loaded
$container.imagesLoaded(function() {
$container.isotope({
itemSelector: '.photo',
masonry: {
columnWidth: 200
}
});
});
// shows the large version of the image
// shows small version of previously large image
function enlargeImage($photo) {
$photos.filter('.large').removeClass('large');
$photo.addClass('large');
$container.isotope('reLayout');
}
$photos.find('a').click(function() {
var $this = $(this),
$photo = $this.parents('.photo');
if ($photo.hasClass('large')) {
// already large, just remove
$photo.removeClass('large');
$container.isotope('reLayout');
} else {
if ($photo.hasClass('has-big-image')) {
enlargeImage($photo);
} else {
// add a loading indicator
$this.append($loadingIndicator);
// create big image
var $bigImage = $('<img>', {
src: this.href
});
// give it a wrapper and appended it to element
$('<div>', {
'class': 'big-image'
})
.append($bigImage)
.appendTo($this)
.imagesLoaded(function() {
$loadingIndicator.remove()
enlargeImage($photo);
});
// add a class, so we'll know not to do this next time
$photo.addClass('has-big-image');
}
}
return false;
});
});
}
</script>
Проблема в том, что после того, как setInterval запускается один раз, все работает так, как ожидалось, когда он снова запустится, изображения больше не будут доступны для просмотра. Если я перемещу часть после//=============//тега в поле, только последнее изображение можно щелкнуть.
Я не могу понять решение для этого (я начинаю с javascript). Может ли кто-нибудь указать мне в правильном направлении?
Обновление: здесь вы можете получить архив проекта, чтобы его можно было запустить локально.
Вам нужно вручную скопировать и пропустить несколько строк из файла данных, чтобы демонстрация работала, потому что она искала разницу предыдущего состояния и текущего состояния файла данных. Проблема в том, что сначала он можно щелкнуть, а потом больше нет.
Ответы
Ответ 1
Я нашел пару вещей, которые нужно изменить в вашем коде:
- Почему
$(document).ready
используется более одного раза? - Нет необходимости использовать
$(function()
-
Поскольку я вижу, что класс фотографии генерируется динамически во время выполнения, а контейнерный класс уже находится в DOM, я изменил событие click
$container.on('click', '.photo a', function() {
Редактировать Пожалуйста, обратите внимание, что код не проверен; Я только что скорректировал код.
Окончательный обновленный код выглядит следующим образом:
var previous = 0;
var current = 0;
loadJSON(function(response) {
// Parse JSON string into object
current = JSON.parse(response);
});
function loadJSON(callback) {
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', 'data.json', true); // Replace 'my_data' with the path to your file
xobj.onreadystatechange = function() {
if (xobj.readyState == 4 && xobj.status == "200") {
// Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode
callback(xobj.responseText);
}
};
xobj.send(null);
}
let lengthOfprevious = previous.length;
setInterval(function() {
loadJSON(function(response) {
// Parse JSON string into object
current = JSON.parse(response);
});
previous = current;
if (lengthOfprevious != current.length) {
UpdateBody(lengthOfprevious);
}
lengthOfprevious = previous.length;
}, 5000);
function UpdateBody(startIndex) {
var newElements = "",
$container = $('#container'),
$photos = $container.find('.photo'),
$loadingIndicator = $('<div class="loading"><span><img src="http://i.imgur.com/IE7iw.gif" /></span></div>');
$(document).ready(function() {
for (let i = startIndex; i < previous.length; i++) {
newElements = "";
newElements +=
'<div class="photo element-item">' +
'<a href="' + previous[i].image + '"><img class="small-image" src="' + previous[i].image + '"/></a>' +
'<a class="weight">' + previous[i].weight + '</a></div>';
var $newElems = $(newElements);
$container.append($newElems).imagesLoaded(function() {
$container.isotope('insert', $newElems);
});
}
$container.imagesLoaded(function() {
$container.isotope({
itemSelector: '.photo',
masonry: {
columnWidth: 200
}
});
});
// shows the large version of the image
// shows small version of previously large image
function enlargeImage($photo) {
$photos.filter('.large').removeClass('large');
$photo.addClass('large');
$container.isotope('reLayout');
}
$container.on('click', '.photo a', function() {
var $this = $(this),
$photo = $this.parents('.photo');
if ($photo.hasClass('large')) {
// already large, just remove
$photo.removeClass('large');
$container.isotope('reLayout');
} else {
if ($photo.hasClass('has-big-image')) {
enlargeImage($photo);
} else {
// add a loading indicator
$this.append($loadingIndicator);
// create big image
var $bigImage = $('<img>', {
src: this.href
});
// give it a wrapper and appended it to element
$('<div>', {
'class': 'big-image'
})
.append($bigImage)
.appendTo($this)
.imagesLoaded(function() {
$loadingIndicator.remove()
enlargeImage($photo);
});
// add a class, so we'll know not to do this next time
$photo.addClass('has-big-image');
}
}
return false;
});
});
}
Ответ 2
Вы можете заменить блок сценария следующим блоком сценария и попытаться запустить:
<script>
var previous = [];
var current = [];
function loadJSON(callback) {
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', 'data.json', true); // Replace 'my_data' with the path to your file
xobj.onreadystatechange = function() {
if (xobj.readyState == 4 && xobj.status == "200") {
// Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode
callback(xobj.responseText);
}
};
xobj.send(null);
}
function start(){
loadJSON(function(response) {
previous = current;
current = JSON.parse(response);
if (previous.length != current.length) {
UpdateBody(current);
}
});
}
function UpdateBody(data) {
var newElements = "";
for (var i in data) {
newElements +=
'<div class="photo element-item">' +
'<a href="' + data[i].image + '"><img class="small-image" src="' + data[i].image + '"/></a>' +
'<br/>' +
'<a class="weight">' + data[i].weight + '</a>' +
'</div>';
}
if(newElements!=""){
var $newElems = $(newElements);
$('#container').append($newElems).imagesLoaded(function() {
$('#container').isotope('insert', $newElems);
});
}
}
$(document).ready(function(){
start();
setInterval(start, 5000);
var $container = $('#container'),
$photos = $container.find('.photo'),
$loadingIndicator = $('<div class="loading"><span><img src="http://i.imgur.com/IE7iw.gif" /></span></div>');
// trigger Isotope after images have loaded
$container.imagesLoaded(function() {
$container.isotope({
itemSelector: '.photo',
masonry: {
columnWidth: 200
}
});
});
// shows the large version of the image
// shows small version of previously large image
function enlargeImage($photo) {
$container.find('.photo.large').removeClass('large');
$photo.addClass('large');
$container.isotope('layout');
}
$(document).on('click','#container .photo a',function() {
var $this = $(this),
$photo = $this.parent('.photo');
if ($photo.hasClass('large')) {
// already large, just remove
$photo.removeClass('large');
$container.isotope('layout');
} else {
if ($photo.hasClass('has-big-image')) {
enlargeImage($photo);
} else {
// add a loading indicator
$this.append($loadingIndicator);
// create big image
var $bigImage = $('<img>', {
src: this.href
});
// give it a wrapper and appended it to element
$('<div>', {
'class': 'big-image'
})
.append($bigImage)
.appendTo($this)
.imagesLoaded(function() {
$loadingIndicator.remove()
enlargeImage($photo);
});
// add a class, so we'll know not to do this next time
$photo.addClass('has-big-image');
}
}
return false;
});
});
</script>
Я многое изменил на вашем коде. которые помогли мне организовать код. но самая важная часть клика не работает:
$(document).on('click','#container.photo a',function() {
Я привязал обработчик события клика, как указано выше, потому что элементы добавляются после загрузки страницы. поэтому он должен работать с элементами, которые добавляются позже, чем время, когда обработчик прикреплен.
вы можете больше узнать о функции jQuery.on
и попытаться понять, как это работает.
Ответ 3
проблема в $photos.find('a').click(
- это привязка, щелкнув на существующие элементы, поэтому новый ее не вызывает щелчка.
$('.items_wrap_class').on('click', 'a', function() {/* all existings an new items clicks will fire this */})
UPD
В вашем случае делегируйте #container
.photo a
обработку кликов.
замените $photos.find('a').click( function() {... })
с
$('#container').on('click', '.photo a', function() {... })