Javascript-форум (https://javascript.ru/forum/)
-   Элементы интерфейса (https://javascript.ru/forum/dom-window/)
-   -   Добавление background-X (https://javascript.ru/forum/dom-window/74684-dobavlenie-background-x.html)

madeas 31.07.2018 15:59

Добавление background-X
 
Всем привет.
Ребята, помогите составить скрипт.
Нужно при помощи инпутов задать блоку background-image и другие свойства.
Т.е., при вводе ссылки в 1 поле, в блоке #back появляется картинка, которая корректируется при помощи полей, расположенных ниже.
Как правильно составить скрипт? Думал сделать выведение через value, но не уверен, что получится. Знаний js пока не хватает.
Набросал разметку в песочнице https://jsfiddle.net/Lbqfp9g7/

Dilettante_Pro 31.07.2018 16:46

Для начала - только url.
Можно попробовать этот: "https://javascript.ru/cat/list/donkey.gif"

<style>
* {
  box-sizing: border-box;
  padding: 0;
  margin: 0;
}

label,
ul,
p {
  margin-bottom: 0;
}

.back_flex ul li {
  list-style: none;
  display: inline-block;
}

.back_flex {
  display: flex;
  align-items: center;
  margin: 15px 0;
}

.back_flex p {
  margin-right: 15px;
}

#backpx {
  width: 50px;
}

#back {
  width: 267px;
  height: 267px;
  background-color: rgb(0, 0, 0);
  display: flex;
  position: relative;
}
</style>
<div class='container p-3'>
  <div class='row align-items-center'>

    <div class='col-lg-6'>

      <div class='back_flex'>
        <p>background-image:</p>
        <ul>
          <li>url(<input type='text' id=''>);</li>
        </ul>
      </div>

      <div class='back_flex'>
        <p>background-repeat:</p>
        <ul>
          <li><label><input type='radio' name='repeat' id='' checked>no-repeat;</label></li>
          <li><label><input type='radio' name='repeat' id=''>repeat;</label></li>
          <li><label><input type='radio' name='repeat' id=''>repeat-x;</label></li>
          <li><label><input type='radio' name='repeat' id=''>repeat-y;</label></li>
        </ul>
      </div>

      <div class='back_flex'>
        <p>background-position: </p>
        <ul>
          <li>Left <label><input id='backpx' type='number' min='0' max='100' id=''>%</label></li>
          <li>Top <label><input id='backpx' type='number' min='0' max='100' id=''>%</label></li>
        </ul>
      </div>

      <div class='back_flex'>
        <p>background-size: </p>
        <ul>
          <li><label><input id='backpx' type='number' id=''>px</label></li>
          <li><label><input type='radio' id='' name='size'>cover</label></li>
          <li><label><input type='radio' id='' name='size'>repeat</label></li>
          <li><label><input type='radio' id='' name='size'>no-repeat</label></li>
        </ul>
      </div>

    </div>

    <div class='col-lg-6'>
      <div id='back'></div>
    </div>

  </div>
</div>
<script>
document.querySelector('input[type=text]').onchange = function() {
    document.querySelector('#back').style.backgroundImage = 'url(' + this.value + ')';
}
</script>

Nexus 31.07.2018 17:00

<div class='container p-3'>
<style>* {
  box-sizing: border-box;
  padding: 0;
  margin: 0;
}

label,
ul,
p {
  margin-bottom: 0;
}

.back_flex ul li {
  list-style: none;
  display: inline-block;
}

.back_flex {
  display: flex;
  align-items: center;
  margin: 15px 0;
}

.back_flex p {
  margin-right: 15px;
}

#backpx {
  width: 50px;
}

#back {
  width: 267px;
  height: 267px;
  background-color: rgb(0, 0, 0);
  display: flex;
  position: relative;
}
</style>
  <div class='row align-items-center'>

    <div class='col-lg-6'>

      <div class='back_flex'>
        <p>background-image:</p>
        <ul>
          <li>url(<input type='text' name="backgroundImage">);</li>
        </ul>
      </div>

      <div class='back_flex'>
        <p>background-repeat:</p>
        <ul>
          <li><label><input type='radio' name='backgroundRepeat' value="no-repeat" checked>no-repeat;</label></li>
          <li><label><input type='radio' name='backgroundRepeat' value="repeat">repeat;</label></li>
          <li><label><input type='radio' name='backgroundRepeat' value="repeat-x">repeat-x;</label></li>
          <li><label><input type='radio' name='backgroundRepeat' value="repeat-y">repeat-y;</label></li>
        </ul>
      </div>

      <div class='back_flex'>
        <p>background-position: </p>
        <ul>
          <li><label>Left <input type='text' name="backgroundPositionLeft"></label></li>
          <li><label>Top <input type='text' name="backgroundPositionTop"></label></li>
        </ul>
      </div>

      <div class='back_flex'>
        <p>background-size: </p>
        <ul>
          <li><label><input type='text' name="backgroundSize"></label></li>
          <li><label><input type='radio' name="backgroundSize" value='cover'>cover</label></li>
          <li><label><input type='radio' name="backgroundSize" value='repeat'>repeat</label></li>
          <li><label><input type='radio' name="backgroundSize" value='no-repeat'>no-repeat</label></li>
        </ul>
      </div>

    </div>

    <div class='col-lg-6'>
      <div id='back'></div>
    </div>

  </div>
</div>
<script>
(function() {
  const container = document.getElementById('back');
  const inputList = [].slice.call(document.querySelectorAll('input'));
  const index = inputList.reduce(function(res, item) {
      if (item.name in res) {
          if (res[item.name] instanceof Array)
              res[item.name].push(item);
          else
              (res[item.name] = [res[item.name]]).push(item);
      } else
          res[item.name] = item;

      return res;
  }, {});


  inputList.forEach(function(node) {
      const IS_RADIO = node.type === 'radio';

      node.addEventListener(IS_RADIO ? 'change' : 'input', function() {
          let value;
          if (this.name.indexOf('backgroundPosition') === 0) {
              return container.style.backgroundPosition =
                  index.backgroundPositionLeft.value +
                  index.backgroundPositionTop.value;
          } else if (this.name === 'backgroundSize') {
              value = index[this.name].filter(function(node) {
                  return node.type === 'text';
              }).shift().getAttribute('value');
              if (!value || value.trim().length) {
                  value = index[this.name].filter(function(node) {
                      return node.type !== 'text' && node.checked;
                  });
                  if (!value.length)
                      return;

                  value = value.shift().getAttribute('value');
              };
          } else if (this.name === 'backgroundImage')
              value = 'url(' + this.value + ')';
          else
              value = this.value;

          container.style[this.name] = value;
      });
  });
})()
</script>

madeas 31.07.2018 17:33

Nexus,
Спасибо. Вообще я предполагал сделать так же, как предложил Dilettante_Pro, но мне кажется, так получилось бы более громоздко.
Dilettante_Pro, спасибо. Я был на верном пути)

j0hnik 31.07.2018 19:12

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
	<style>
	* {
		box-sizing: border-box;
		padding: 0;
		margin: 0;
	}

	label,
	ul,
	p {
		margin-bottom: 0;
	}

	.back_flex ul li {
		list-style: none;
		display: inline-block;
	}

	.back_flex {
		display: flex;
		align-items: center;
		margin: 15px 0;
	}

	.back_flex p {
		margin-right: 15px;
	}

	#backpx {
		width: 50px;
	}

	#back {
		width: 267px;
		height: 267px;
		background-color: rgb(0, 0, 0);
		display: flex;
		position: relative;
	}
</style>
</head>
<body>
	<div class='container p-3'>
		<div class='row align-items-center'>

			<div class='col-lg-6'>

				<div class='back_flex'>
					<p>background-image:</p>
					<ul>
						<li>url(<input type='text' id='url' value="https://javascript.ru/cat/list/donkey.gif">);</li>
					</ul>
				</div>

				<div class='back_flex'>
					<p>background-repeat:</p>
					<ul>
						<li><label><input type='radio' name='repeat' id='' checked>no-repeat</label></li>
						<li><label><input type='radio' name='repeat' id=''>repeat</label></li>
						<li><label><input type='radio' name='repeat' id=''>repeat-x</label></li>
						<li><label><input type='radio' name='repeat' id=''>repeat-y</label></li>
					</ul>
				</div>

				<div class='back_flex'>
					<p>background-position: </p>
					<ul>
						<li>Left <label><input id='posX' type='number' min='0' max='100' value="0">%</label></li>
						<li>Top <label><input id='posY' type='number' min='0' max='100' value="0">%</label></li>
					</ul>
				</div>

				<div class='back_flex'>
					<p>background-size: </p>
					<ul>
						<li><label><input type='number' id='size' value="30">px</label></li>
						<li><label><input type='checkbox' id='size2' name='size'>cover</label></li>
					</ul>
				</div>

			</div>

			<div class='col-lg-6'>
				<div id='back'></div>
			</div>

		</div>
	</div>
	<script>
		var back = document.querySelector("#back"),
		x = document.querySelector("#posX"),
		y = document.querySelector('#posY'),
		size = document.querySelector('#size'),
		size2 = document.querySelector('#size2');
		(style=()=>{
			back.style.background = `url(${document.querySelector("#url").value}) black ${document.querySelector('[name="repeat"]:checked').parentNode.textContent} ${x.value}% ${y.value}%`;
			back.style.backgroundSize = size2.checked?'cover':size.value+'px';
		})();
		document.querySelectorAll('input').forEach(el=>el.oninput=style);
	</script>
</body>
</html>

madeas 01.08.2018 12:31

j0hnik,
а можно сделать поля независимыми? Сейчас, когда выбираешь пункты, они не активируются до нажатия на background-size. Т.е. чтобы другие изменения заработали, придется стирать size и писать еще раз.

Dilettante_Pro 01.08.2018 13:01

madeas,
У меня пример j0hnik прекрасно работает в Chrome - изменения срабатывают сразу по любому параметру - и совсем не работает в IE.
Стрелочные функции поддерживают не все браузеры

madeas 01.08.2018 13:50

Dilettante_Pro,
тогда хз, в хромиуме приходится обновлять значение других полей, чтобы сработали repeat'ы. Сами по себе они не меняются почему-то.

madeas 01.08.2018 14:18

Dilettante_Pro,
похоже это особенность браузера, эх... в фоксе и правда норм работает.

Dilettante_Pro 01.08.2018 14:20

Цитата:

Сообщение от madeas
в хромиуме приходится обновлять значение других полей

Именно в примере j0hnik пост 5 здесь в теме через Посмотреть?
Вообще Chrome поддерживает стрелочные функции с версии 45.0
У меня 67.0.3396.99

madeas 01.08.2018 14:34

Dilettante_Pro,
в его примере, через "Посмотреть", так же. Не работают репиты и переключение px/cover. Изменения вступают в силу только после изменений позиции (лефт/топ). Cover работает, но тоже барахлит)

Dilettante_Pro 01.08.2018 14:46

А как такой вариант?
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
	<style>
	* {
		box-sizing: border-box;
		padding: 0;
		margin: 0;
	}

	label,
	ul,
	p {
		margin-bottom: 0;
	}

	.back_flex ul li {
		list-style: none;
		display: inline-block;
	}

	.back_flex {
		display: flex;
		align-items: center;
		margin: 15px 0;
	}

	.back_flex p {
		margin-right: 15px;
	}

	#backpx {
		width: 50px;
	}

	#back {
		width: 267px;
		height: 267px;
		background-color: rgb(0, 0, 0);
		display: flex;
		position: relative;
	}
</style>
</head>
<body>
	<div class='container p-3'>
		<div class='row align-items-center'>

			<div class='col-lg-6'>

				<div class='back_flex'>
					<p>background-image:</p>
					<ul>
						<li>url(<input type='text' id='url' value="https://javascript.ru/cat/list/donkey.gif">);</li>
					</ul>
				</div>

				<div class='back_flex'>
					<p>background-repeat:</p>
					<ul>
						<li><label><input type='radio' name='repeat' id='' checked>no-repeat</label></li>
						<li><label><input type='radio' name='repeat' id=''>repeat</label></li>
						<li><label><input type='radio' name='repeat' id=''>repeat-x</label></li>
						<li><label><input type='radio' name='repeat' id=''>repeat-y</label></li>
					</ul>
				</div>

				<div class='back_flex'>
					<p>background-position: </p>
					<ul>
						<li>Left <label><input id='posX' type='number' min='0' max='100' value="0">%</label></li>
						<li>Top <label><input id='posY' type='number' min='0' max='100' value="0">%</label></li>
					</ul>
				</div>

				<div class='back_flex'>
					<p>background-size: </p>
					<ul>
						<li><label><input type='number' id='size' value="30">px</label></li>
						<li><label><input type='checkbox' id='size2' name='size'>cover</label></li>
					</ul>
				</div>

			</div>

			<div class='col-lg-6'>
				<div id='back'></div>
			</div>

		</div>
	</div>
	<script>
		var back = document.querySelector("#back"),
		x = document.querySelector("#posX"),
		y = document.querySelector('#posY'),
		size = document.querySelector('#size'),
		size2 = document.querySelector('#size2');
		function  style() {
			back.style.background = `url(${document.querySelector("#url").value}) black ${document.querySelector('[name="repeat"]:checked').parentNode.textContent} ${x.value}% ${y.value}%`;
			back.style.backgroundSize = size2.checked?'cover':size.value+'px';
		};
                style();
		[].forEach.call(document.querySelectorAll('input'), function(el) { el.onchange=style});
		[].forEach.call(document.querySelectorAll('input'), function(el) { el.oninput=style});
	</script>
</body>
</html>

madeas 01.08.2018 15:00

Dilettante_Pro,
https://my-files.ru/dko70m пришлось на телефон снимать))

Dilettante_Pro 01.08.2018 15:10

madeas,
Посмотрел. Очень странно. У меня нормально работает - на все параметры сразу реагирует.
Значит, дело не в стрелочных функциях...

Dilettante_Pro 01.08.2018 15:24

madeas,
Изменил назначение обработчика в пост 12. Посмотрите.

madeas 01.08.2018 15:36

Dilettante_Pro,
не, ничего не поменялось. Это видимо браузер. Нормально работает лефт/топ и позиция через поле. Радио и чеки нет.
Кстати, а как сделать чтобы появилась кнопка "просмотреть" ?)

Nexus 01.08.2018 15:49

madeas, скорее всего событие "input" не срабатывает на радио-баттонах.
Про форматирование на форуме: http://javascript.ru/formatting

Dilettante_Pro 01.08.2018 16:12

Цитата:

Сообщение от Nexus
скорее всего событие "input" не срабатывает на радио-баттонах.

Назначил два обработчика в пост 12.

Если только change - не очень динамично работает

Nexus 01.08.2018 16:16

Dilettante_Pro, а почему не так?
[].forEach.call(document.querySelectorAll('input'), function(el) {
    el.addEventListener(el.type === 'text' ? 'input' : 'change', style);
});

Dilettante_Pro 01.08.2018 16:19

Nexus,
Методом копипасте, по-быстрому:) - для посмотреть
Сначала input поменял на change - не очень понравилось, добавил второй:write:

madeas 01.08.2018 16:51

Я если честно запутался) Подскажите, как переправить чтобы инпуты срабатывали? п.с. Попробую сделать с просмотром)) Секунду)

madeas 01.08.2018 16:59

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
      * {
        box-sizing: border-box;
        padding: 0;
        margin: 0;
      }

      ul li {
        list-style: none;
        display: inline-block;
      }

      .back_style {
        font-size: 16px;
      }

      #back {
        width: 267px;
        height: 267px;
        background-color: rgb(0, 0, 0);
        display: flex;
        position: relative;
      }

      .d-flex {
        display: flex;
        margin-bottom: 1rem;
      }

      .space-around {
        justify-content: space-around;
      }

      .flex-column {
        flex-direction: column;
      }

    </style>

    <body>

      <div class='d-flex'>
        <p>background-image:</p>
        <ul>
          <li>url(<input type='text' id='bgImage' value="https://javascript.ru/cat/list/donkey.gif">);</li>
        </ul>
      </div>

      <div class='d-flex space-around'>
        <div class='mr-2'>
          <h5>background-repeat:</h5>
          <ul class='d-flex flex-column'>
            <li><input type='radio' name='repeat' id='norep' checked><label for='norep'>no-repeat</label></li>
            <li><input type='radio' name='repeat' id='repXY'><label for='repXY'>repeat</label></li>
            <li><input type='radio' name='repeat' id='repX'><label for='repX'>repeat-x</label></li>
            <li><input type='radio' name='repeat' id='repY'><label for='repY'>repeat-y</label></li>
          </ul>
        </div>
        <div class='mx-2'>
          <h5>background-size:</h5>
          <ul class='d-flex flex-column'>
            <li><label id='bnoradio'><input type='number' id='sizeIn' value='150' name='size' class='adstl bsize'> px</label></li>
            <li class='bsckeck'><input type='checkbox' id='sizeOne' name='size'><label for='sizeOne'>cover</label></li>
            <li class='bsckeck'><input type='checkbox' id='sizeTwo' name='size'><label for='sizeTwo'>contain</label></li>
          </ul>
        </div>
        <div class='ml-2'>
          <h5>background-position:</h5>
          <ul class='d-flex flex-column'>
            <li>Left: <label><input id='posX' type='number' min='0' max='100' value='50' class='adstl bsize'> %</label></li>
            <li>Top: <label><input id='posY' type='number' min='0' max='100' value='70' class='adstl bsize'> %</label></li>
          </ul>
        </div>
      </div>

      <div id='back'></div>

      <script>
        var back = document.querySelector("#back"),
          x = document.querySelector("#posX"),
          y = document.querySelector('#posY'),
          so = document.querySelector('#sizeOne'),
          st = document.querySelector('#sizeTwo'),
          si = document.querySelector('#sizeIn');
        (style = () => {
          back.style.background = `url(${document.querySelector("#bgImage").value}) black ${document.querySelector('[name="repeat"]:checked').parentNode.textContent} ${x.value}% ${y.value}%`;
          back.style.backgroundSize = so.checked ? 'cover' : st.checked ? 'contain' : si.value + 'px';
        })();
        document.querySelectorAll('input').forEach(el => el.oninput = style);

      </script>
    </body>
  </head>

</html>


Получилось))
Я слегка подкорректировал, в принципе и так нормально, но такие тонкости не все поймут, психанут и закроют страничку)

Dilettante_Pro 01.08.2018 17:28

madeas,
Что-то я в результате не понял, почему у вас раньше не работало?

madeas 01.08.2018 17:37

Dilettante_Pro,
не работают только радио и чеки. Вернее работают, но после изменений в других полях. Я так понял, что это браузер так себя ведет, хз почему. Так что оставлю пока как есть, может со временем приду к нужному решению.

Dilettante_Pro 01.08.2018 17:48

madeas,
а смотрели последнюю версию пост 12?
Работают радио?
Можно также с использованием варианта Nexus

madeas 01.08.2018 17:51

Dilettante_Pro,
пробовал. это браузер. на телефоне в хроме норм, в других браузерах тоже по разному, но работают.

Dilettante_Pro 01.08.2018 18:42

Попробуйте вот этот вариант back.style.background
back.style.background = 'url(' + document.querySelector("#bgImage").value+') black '+ document.querySelector('[name="repeat"]:checked').parentNode.textContent +' '+x.value+'% '+y.value+'%';

j0hnik 01.08.2018 19:39

Dilettante_Pro, я так и начал с ', но потом запутался стер и поставил ` они удобней =)

Dilettante_Pro 02.08.2018 09:52

j0hnik,
Да я уже всячески с бубнами танцую - у ТС что-то странное...
Стоит посмотреть в консоли насчет ошибок и назначения обработчиков

ЗЫ:
Цитата:

Сообщение от j0hnik
и поставил ` они удобней

в IE Edge выдает ошибку неправильный символ

madeas 02.08.2018 09:53

Dilettante_Pro,
так это же тоже самое фактически) не помогает. Это всетаки хромиум убонтовский так работает. Жаль что нельзя оставить 2-3 браузера с одинаковой поддержкой, а остальные заблокировать нафиг))

Dilettante_Pro 02.08.2018 09:57

Цитата:

Сообщение от madeas
оставить 2-3 браузера с одинаковой поддержкой, а остальные заблокировать нафиг

Ну да, и клиентам принудительно устанавливать правильный браузер...

Консоль-то что-то говорит? Ошибки? Обработчики на инпуты устанавливаются?

Цитата:

Сообщение от madeas
так это же тоже самое фактически)

Не совсем, в некоторых браузерах не работает `.

Nexus 02.08.2018 10:19

Цитата:

Сообщение от madeas
так это же тоже самое фактически)

Нет, совсем не тоже самое.
https://developer.mozilla.org/ru/doc...mplate_strings

madeas 06.08.2018 20:34

Ребята, подскажите, а как разбить этот бэкграунд на части, чтобы бэкграунд превратился в в бэкграунд-имадже, а другие давали свои параметры?


var back = document.querySelector("#back"),
        x = document.querySelector("#posX"),
        y = document.querySelector('#posY'),
        so = document.querySelector('#sizeOne'),
        st = document.querySelector('#sizeTwo'),
        si = document.querySelector('#sizeIn');
      (style = () => {
        back.style.backgroundImage = 'url(' + document.querySelector("#bgImage").value + ') ';
        back.style.backgroundRepeat = document.querySelector('[name="repeat"]:checked');
        back.style.backgroundPosition = + x.value + '% ' + y.value + '%';
        back.style.backgroundSize = so.checked ? 'cover' : st.checked ? 'contain' : si.value + 'px';
      })();      
      document.querySelectorAll('input').forEach(el => el.oninput = style);


Вроде бы сделал правильно, но не работает. В чем ошибка?

madeas 06.08.2018 22:49

настроил.

var back = document.querySelector("#back"),
  x = document.querySelector("#posX"),
  y = document.querySelector('#posY'),
  so = document.querySelector('#sizeOne'),
  st = document.querySelector('#sizeTwo'),
  si = document.querySelector('#sizeIn');
(style = () => {
  back.style.backgroundImage = 'url(' + document.querySelector("#bgImage").value + ') ';
  back.style.backgroundSize = so.checked ? 'cover' : st.checked ? 'contain' : si.value + 'px';
  back.style.backgroundRepeat = document.querySelector('[name="repeat"]:checked').parentNode.textContent;
  back.style.backgroundPosition = y.value + '%' + x.value + '%';
})();
document.querySelectorAll('input').forEach(el => el.oninput = style);


Часовой пояс GMT +3, время: 00:38.