@qghoul666
Студент 4 курса. Back-end. Java. Spring.

Как реализовать поочерёдную загрузку изображений и их предпросмотр, и возможность удаления по кнопке?

Собственно, у меня есть сгенерированный код js для добавления в форму изображений пользователем и их предпросмотра. Но глобально есть две проблемы.
1) При удалении изображений по кнопке происходит смена индексов (то ли у файлов в input, то ли у кнопок внутри div`a class="image-preview") в связи с этим если удалять начиная с конца к началу по порядку, то всё отлично работает, но если делать с начала в конец или произвольно, то всегда остаётся 1-2 файла в input'е, хотя все изображения из предпросмотра удалены.
пример некорректной работы

Показывает что файла два, а изображение осталось одно.
65d26628b72bb800628754.png
65d262285f79f607538959.png

2) Уже менее критично, но всё же хочу реализовать возможность поочерёдного добавления изображений, а то в текущем состоянии при добавлении новой картинки с помощью input старые файлы автоматически очищаются, а мне это не нужно, ведь для очищения у юзера будут специальные кнопки возле каждого изображения в контейнере предпросмотра. Очевидно нужно убрать очищение сгенерированного innerHtml внутри js функции, но непонятно как сделать так чтобы сохранялись не только картинки в контейнере предпросмотра, но и чтобы фактически файлы внутри input`a тоже сохранялись.

function checkFileCount(input) {
    if (input.files.length > 5) {
        alert("Вы можете выбрать не более пяти файлов."); //хочу чтобы пользователь не мог загрузить суммарно больше 5 файлов
        input.value = ''; // очищаем значение поля input, чтобы пользователь мог выбрать файлы заново
    } else {
        previewImages(input); //вызываю функцию отвечающую за предпоказ 
    }
}

function previewImages(input) {
    var files = input.files; 
    var preview = document.querySelector('.image-preview'); 
//выбираем контейнер где будут отображаться картинки
    preview.innerHTML = ''; 
//очищение этого контейнера от изображений загруженных в предыдущий раз 
 <b>//эту строку нужно будет закомментировать чтобы реализовать многократное добавление без очищения содержимого input,
// но не всё так просто, проблема в том что закомментировав её старые изображения в предпросмотре будут сохраняться,
// но в input эти старые изображения будут удалены (в пункте 2 говорил про это)</b>

    for (var i = 0; i < files.length; i++) { //цикл для чтения изображений
        var file = files[i];
        var reader = new FileReader();
        reader.onload = (function(file, index) {
            return function(e) {
                var image = document.createElement('img'); 
//реализуем предпросмотр выбранных изображений
                image.src = e.target.result;
                image.classList.add('preview-image');
                preview.appendChild(image);

                var removeButton = document.createElement('button'); 
//кнопка удаления для каждого изображения
                removeButton.textContent = 'X';
                removeButton.classList.add('remove-button');
                removeButton.onclick = function() { 
//добавляем функцию чтобы при нажатии на кнопку удалялись изображения из предпросмотра и из файлов input'a
                    preview.removeChild(image);
                    preview.removeChild(removeButton);
                    // Удаляем файл из выбранных файлов
                    input.files = removeFile(input.files, index);
                };
                preview.appendChild(removeButton);
            };
        })(file, i); 
        reader.readAsDataURL(file); 
    }
}

<b>// Функция для удаления файла из списка файлов по индексу. 
//В ней как раз таки зарыта собака, потому что после удаления одного из элементов
// индексы других меняются и некоторые  дальнейшие удаления происходят некорректно,
// хотя если удалять начиная с конца, то всё работает корректно (в пункте 1 писал об этом)</b>
function removeFile(files, index) {
    var newFiles = new DataTransfer();
    for (var i = 0; i < files.length; i++) {
        if (i !== index) {
            newFiles.items.add(files[i]);
        }
    }
    return newFiles.files;
}

<div class="cont">
            <label class="filter" for="images">Додати фотографію</label>
            <input type="file" id="images" name="images" accept="image/*" onchange="checkFileCount(this)" multiple required>
        </div>

Исходный html код

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" type="text/css" href="css/styles2.css">
    <title>Add bus form</title>
</head>
<body>

<header>
    <ul class="menu">
    <div class="leftPart"><li id="findPet"><a href="/pets">Знайти тварину</a></li>
    <li><a href="/rules">Правила адопції</a></li>
    <li><a href="/help">Допомогти</a></li>
    <li><a href="/aboutProject">Про проєкт</a></li>
</div>
    <div class="rightPart"><li id="createAdd"><a href="/myProfile">Додати оголошення</a></li>
    <li id="login"><a href="/authorization">Профіль</a></li>
</div>
</ul>
</header>
<div class="center-global-container">
            <div class="errorMessage">${errorMessage}</div>   
    <div class="filters"> 
        <form class="addForm" action="/cats/add" method="post">
            </div>

        <div class="cont">
            <label class="filter" for="images">Додати фотографію</label>
            <input type="file" id="images" name="images" accept="image/*" onchange="checkFileCount(this)" multiple required>
        </div>
        <div class="image-preview"></div>
        <button type="submit" name="sumbit" class="sumbit-form">Опублікувати оголошення</button>
    </form>
    </div>
</div>
</body>
</html>

/*Обнуление*/
 *, // Половину стилей пришлось удалить из-за ограничения по объему, но вроде все важные есть
 *:before,
 *:after{
    padding: 0;
    margin: 0;
    border: 0;
    box-sizing: border-box;
 }
.image-preview {
    display: flex;
}
.image-preview img {
    width: 100px;
    height: 100px;
    object-fit: cover; /* чтобы изображение не растягивалось и не сжималось, сохраняя соотношение сторон */
    margin: 5px;
}

.remove-button {
    margin-left: -20px;
    height: 15px;
    width: 15px;
    margin-top: 5px;
    display: block;
    color: red;
}
.remove-button:hover {
    cursor: pointer;
    background-color: pink;
}
.filters {
    background-color: #788AB2;
    padding: 10px 20px;
    width: 590px;
    height: 10%;
    box-sizing: border-box;
    font-size: 20px;
    font-family: Tahoma;
    color: white;
    display: flex;
    flex-direction: column;
}
.filters label, .filters select, .filters option {
    flex: 1;
    display: inline-block;
    margin-bottom: 12px;
    line-height: 26px;
}
.filters label { 
    margin-top: 12px
}
.filters p{
    align-self: center;
    justify-self: center;
    font-size: 24px;
    margin-bottom: 10px;
}
.cont {
    display: flex;
    align-items: center;
    justify-content: space-between;
}
.filters select {
    position: relative;
    display: block;
    flex: 3.1;
    margin: 5px 0;
    font-family: 'Open Sans', 'Helvetica Neue', 'Segoe UI', 'Calibri', 'Arial', sans-serif;
    font-size: 18px;
    color: #60666d;
    flex-basis: 50px;
}
.center-global-container{
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
}
.addForm-container {
    width: 32.5%;
    min-width: 325px;
    display: flex;
    flex-direction: column;
}
.addForm {
    width: 100%;
    display: flex;
    flex-direction: column;
}
.errorMessage{
    margin-top: 0px;
    margin-bottom: 10px;
    font-size: 1.25rem;
    color: red;
}

  • Вопрос задан
  • 77 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы