Изотоп и javascript - элементы больше не кликабельны после добавления нового - PullRequest
0 голосов
/ 20 мая 2018

Я пытаюсь составить таблицу изображений, загруженных из 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 все работает как положено, при повторном запуске изображения перестают щелкать мышью. Если я перемещу деталь после // ============ // в теге for, только последнее изображение кликабельно.

Я не могу найти решение для этого (я новичок в javascript). Может кто-нибудь указать мне правильное направление?

Обновление : Здесь вы можете получить архив проекта, чтобы можно было запустить его локально.

Вам необходимо вручную скопировать и вставить несколько строк из файла данных для демонстрацииработать, потому что он ищет разницу предыдущего состояния и текущего состояния файла данных.Проблема в том, что сначала он кликабелен, а потом уже нет.

Ответы [ 3 ]

0 голосов
/ 13 июня 2018

Я нашел пару вещей, которые нужно изменить в вашем коде:

  1. Почему $(document).ready используется более 1 раза?
  2. Нет необходимости использовать $(function()
  3. Поскольку я вижу, что класс фотографий генерируется динамически во время выполнения, а класс контейнера уже находится в 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;
        });

    });
}
0 голосов
/ 23 июня 2018

Вы можете заменить свой блок скриптов следующим блоком скриптов и попробовать запустить:

<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 и попытаться понять, как она работает.

0 голосов
/ 11 июня 2018

проблема в $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() { ... })

...