Неповторяющийся случайный фон

102
17 февраля 2021, 06:50

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

const buttonChangeTheme = document.getElementById('changeTheme'); 
const body = document.getElementsByTagName('body')[0]; 
let themes = [ 
  'url("https://solovey.su/image/download/id=1641&type=original")', 
  'url("http://www.hqwallpapers.ru/wallpapers/animals/myshka-s-buketom.jpg")', 
  'url("http://www.gandex.ru/upl/oboi/gandex.ru-19837_30bd8502831492b543db9289b08aa491.jpg")', 
  'url("http://planetakartinok.net/photo/0-0/9174_1363118876.jpg")', 
  'url("http://lookw.ru/1/487/1402241735-oboi-1920h1080.-planeta-obezyan-21.jpg")' 
]; 
let themesAnother = [] 
let themesAnother1 = new Set(themesAnother); 
let difference = [...new Set([...themes].filter(x => !themesAnother1.has(x)))]; 
//сортировка на уникальный фон 
buttonChangeTheme.onclick = function() { 
  if (difference.length !== 0) { 
    body.style.backgroundImage = difference[Math.floor(Math.random() * (difference.length - 1 + 1)) + 1]; 
    themesAnother.push(body.style.backgroundImage); 
    themes.splice(body.style.backgroundImage - 1, 1); 
  } 
};
body { 
  text-align: center; 
  font-family: sans-serif; 
  background-size: cover 
}
<input type="button" id="changeTheme" value="Смена темы" />

Попытался сделать попроще формулу, для того, чтобы разобраться, где скрывается ошибка, но запутался лишь больше. Данная функция должна выводить случайный числа из массива, также не повторяясь. https://jsfiddle.net/Indy660/6d7g9hyk/

let themes=[1,2,3,4,5,6,7,8,9]
let themesAnother =[]
buttonChangeTheme.onclick = function() {
    if (themes!==0) {
        let fone = themes[Math.floor(Math.random() * (themes.length - 1 + 1)) + 1];
        themesAnother.push(fone);
        themes.splice(fone-1,1);
    } 
}
Answer 1
  • Оставляем только уникальный набор изображений: Set.
  • Сортируем в случайном порядке единожды: sort.
  • Выбираем первое изображение из массива при смене фонового изображения: splice.

// Кнопка для изменения фонового изображения. 
const BUTTON = document.querySelector('button[name="theme"]'); 
 
// Исходный массив с изображениями. `Картинка+4` повторяется трижды. 
const SOURCES = [ 
  'https://via.placeholder.com/960x400/100E17/FFFFFF?text=Картинка+4', 
  'https://via.placeholder.com/960x400/9B59B6/FFFFFF?text=Картинка+1', 
  'https://via.placeholder.com/960x400/2ECC71/FFFFFF?text=Картинка+2', 
  'https://via.placeholder.com/960x400/100E17/FFFFFF?text=Картинка+4', 
  'https://via.placeholder.com/960x400/82A43A/FFFFFF?text=Картинка+3', 
  'https://via.placeholder.com/960x400/100E17/FFFFFF?text=Картинка+4' 
]; 
 
// Рабочий массив изображений. Изначально пуст. 
let images = []; 
 
// Добавляем функцию обработчик на событие `click`. 
BUTTON.addEventListener('click', changeTheme); 
 
// Зададим начальное изображение. 
changeTheme(); 
 
// Изменить фоновое изображение. 
function changeTheme(event) { 
  // Если не осталось больше изображений в массиве, 
  // подготовим новый рабочий массив. 
  if (!images.length) prepareImages(); 
 
  // Удаляем первое изображение из массива и 
  // берем первое изображение из массива удаленных. 
  const [image] = images.splice(0, 1); 
   
  // Меняем фоновое изображение. 
  document.body.style.backgroundImage = 'url(' + image + ')'; 
 
  // Если не осталось больше изображений в массиве, блокируем кнопку. 
  // if (!images.length) BUTTON.disabled = true; 
} 
 
// Подготовить рабочий массив изображений. 
function prepareImages() { 
  // Оставим только уникальный набор изображений. 
  images = [...new Set(SOURCES)]; 
   
  // Сортируем единожды в случайном порядке. 
  images.sort((a, b) => Math.random() - 0.5); 
}
body { 
  margin: 0; 
  background-attachment: fixed; 
  background-color: #fafafa; 
  background-repeat: no-repeat; 
  background-position: top; 
  background-size: cover; 
}
<button type="button" name="theme">Сменить фон</button>

Метод splice удаляет/изменяет элемент из массива и в качестве возвращаемого значения содержит массив из удаленных элементов. Если был удален один элемент, то вернется массив из одного элемента.

UPD Добавлено зацикливание при показе изображений.

Answer 2

const buttonChangeTheme = document.getElementById('changeTheme'); 
const body = document.querySelector('body'); // берет первый такой элемент 
let themes = [ 
  'https://solovey.su/image/download/id=1641&type=original', 
  'http://www.hqwallpapers.ru/wallpapers/animals/myshka-s-buketom.jpg', 
  'http://www.gandex.ru/upl/oboi/gandex.ru-19837_30bd8502831492b543db9289b08aa491.jpg', 
  //Из-за Совы обос... Убрал её!) 
  'http://lookw.ru/1/487/1402241735-oboi-1920h1080.-planeta-obezyan-21.jpg' 
]; 
 
let prev; // Для хранения номера предыдущей картинки 
buttonChangeTheme.addEventListener('click', function(){ 
  let check = true; 
  let index; // Для сохранения случайного числа 
  while( check ){ 
    index = Math.floor( Math.random() * themes.length ); 
    //Создаем случайное число и как только оно не равно prev - прерываем цикл 
    if( index !== prev ) { check = false; } 
  } 
   
  console.clear(); console.log( 'Предыдущий: ' + prev + ' // Текущий: ' + index ); 
 
  body.style.backgroundImage = 'url(' + themes[index] + ')'; 
  // Легче так, чем в каждом элементе массика указывать про url(); 
  
  body.style.backgroundColor = `RGB(${Math.random()*200}, ${Math.random()*150}, ${Math.random()*150})`; 
  // Случайный фон, если картинки кривые (а они кривые).  
  // Можно также задать массив цветов и переключать их через тот же index 
 
  prev = index; // В конце запоминаем текущий индекс как "предыдущий" для следующего клика 
});
body { 
  background-size: 100vw 100vh; 
  background-position: fixed; 
}
<input type="button" id="changeTheme" value="Смена темы"/>

Answer 3

Картинки не будет повторяться, если её не будет в массиве.

let bgArr = [ 
  'https://bipbap.ru/wp-content/uploads/2017/10/0_8eb56_842bba74_XL-640x400.jpg', 
  'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRgtN5i-ym2j7nhD7L5VY3l2TpjKKDQjp9wqqiGKW-PQCestJgOvQ', 
  'https://i.uaportal.com/2019/3/1/3.jpg', 
  'https://i.pinimg.com/originals/c6/c4/0d/c6c40d8dd7d307d1b963b28b7af9eafb.jpg', 
  'https://i.ytimg.com/vi/aoh6oUhtiyo/maxresdefault.jpg' 
]; 
 
randomBg(); // запускаем в начале 
$('#change').on('click', randomBg); // и при клике 
 
function randomBg() { 
  console.clear(); 
  if (!bgArr || bgArr != '') { 
    let random = Math.floor(Math.random() * bgArr.length); // Выбираем рандомный индекс по массиву 
    $('body').css('background-image', 'url('+bgArr[random]+')'); // выставляем image для body 
    bgArr.splice(random, 1); // удаляем из массива 
    console.info('Установлен фон '+random); 
  } else console.info('Массив пустой'); 
}
body { 
  background-repeat: no-repeat; 
  background-size: cover; 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> 
 
<input id="change" type="button" value="Сменить фон">

READ ALSO
Не выводит стили на печать

Не выводит стили на печать

Использую bootstrapНа некоторых строках таблицы есть определённый стиль

112
Поиск элемента по дереву в iframe

Поиск элемента по дереву в iframe

Нужно в iframe найти найти блок по классу и удалить егоКак это реализовать на чистом js?

82
Преобразовать строки в ссылки

Преобразовать строки в ссылки

Всем приветЕсть текстовый файл:

104
Как правильно задать центр вращения для анимации SVG элемента?

Как правильно задать центр вращения для анимации SVG элемента?

Есть rect, которому нужно задать анимацию поворота "туда-обратно", неважно через CSS-анимации или через SMIL, анимация всё равно простаяНо возникает...

130