Обработка события onmousemove подразумевает, что мы будем отслеживать перемещение указателя мыши относительно какого-либо элемента, либо относительно всего документа.
Для того обработки события onmousemove мы создадим поздравительную открытку, при наведении на которую за счет использования CSS-свойств 3D трансформаций и перспективы мы будем несколько разворачивать основной блок.
Пожалуй, в этом примере будет больше css-свойств, нежели каких-то нюансов обработки событий, поэтому советую прочитать статью "CSS cвойства элемента. Использование в JavaScript".
Разметка, CSS-стили и начальный JS-код для обработки события onmousemove
Разметка открытки:
1 2 3 4 5 6 |
<div class="birthday-card"> <div> <h1 class="title">Дорогой поcетитель!</h1> <h2 class="subtitle">С днем рождения тебя!</h2> </div> </div> |
Как видите, все очень просто.
CSS-стили
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
@import url('https://fonts.googleapis.com/css?family=Pacifico&display=swap&subset=cyrillic'); * { box-sizing: border-box; font-family: 'Pacifico', cursive; font-size: 1em; } body { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; min-height: 100vh; } .birthday-card { display: flex; align-items: center; justify-content: center; width: 660px; height: 460px; border: 6px solid #fff; background: linear-gradient(rgba(239, 255, 48, 0.49), rgba(211, 31, 48, 0.8)), url(images/birthday.gif) no-repeat right top; -webkit-background-size: auto, 360px; background-size: auto, 360px; box-shadow: 0px 0px 60px rgba(0, 0, 0, 0.6); transition: all 0.4s cubic-bezier(0.39, 0.575, 0.565, 1); } .birthday-card .title, .birthday-card .subtitle { font-weight: 100; color: #F9F8FD; text-align: center; } .birthday-card .title { font-size: 3rem; } .birthday-card .subtitle { font-size: 1.75rem; } |
Стилей намного больше, чем разметки.
JS-код
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function birthdayCard() { const angle = 10; const card = document.querySelector(".birthday-card"); card.addEventListener('mouseout', e => { card.style.transform = `perspective(400px) rotateX(0deg) rotateY(0deg)`; }); card.addEventListener('mousemove', e => { const w = card.clientWidth; const h = card.clientHeight; const y = (e.offsetX - w * 0.5) / w * angle; const x = (1 - (e.offsetY - h * 0.5)) / h * angle; card.style.transform = `perspective(400px) rotateX(${x}deg) rotateY(${y}deg)`; }); } birthdayCard(); |
Обратите внимание, что мы обрабатываем не только событие onmousemove (mousemove при записи его в методе addEventListener()
), меняя css-свойства группы 3D-transform и рассчитывая при этом угол поворота по осям X и Y в зависимости от местоположения курсора мыши (свойства e.offsetX
и e.offsetY
, где e
- это переменная, связанная с объектом события.), но и событие mouseout, которое наступает при выходе указателя мыши за пределы нашего блока .birthday-card
. При обработке события mouseout мы возвращаем наш блок с открыткой в первоначальное положение без поворота по осям X и Y (свойства rotateX(0deg)
и rotateY(0deg)
).
Давайте теперь посмотрим на сам пример:
Добавляем имя пользователя (именинника) в заголовок открытки
А теперь добавим еще возможность задавать имя пользователя в разметку и в стили, дописав кнопку-ссылку и блок с текстовым полем и кнопкой, подтверждающей ввод:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
<style> #userName { position: absolute; bottom: 10px; right: 20px; width: 330px; height: 120px; padding: 20px 10px; text-align: center; display: none; background-color: #fddada; border: 2px solid #d31f30; z-index: 2; } #userName input { padding: 10px; width: 70%; margin: 10px; } #userName input:focus { border: 1px solid #af1111; } #userName *:focus { outline-color: transparent; } #nameBtn { padding: 15px 20px; border-radius: 50%; background-color: #d31f30; color: #fff; border: 2px solid #fff; transition: .5s; cursor: pointer; } #nameBtn:hover, #nameBtn:focus { background-color: #fff; border-color: #af1111; color: #af1111; } #addName { position: fixed; bottom: 10px; right: 20px; background-color: #d31f30; color: #fff; padding: 10px 20px; text-decoration: none; } #addName:hover { background-color: #af1111; } </style> <body> <a id="addName" href="#userName">Задать имя</a> <div id="userName"> <input type="text" id="name" name="name" placeholder="Введите имя именинника"> <button id="nameBtn">Ок</button> </div> <div class="birthday-card"> ... </div> <body> |
Добавляем JS-код для обработки данных, введенных пользователем:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
//дописываем код внутри функции birthdayCard() function birthdayCard() { ...;// тот код, что был ранее написан //получаем ссылки на нужные нам элементы и кнопки const cardTitle = document.querySelector(".title"), addName = document.getElementById('addName'), userName = document.getElementById('userName'); // обрабатываем клик на кнопке-ссылке "Задать имя" addName.addEventListener('click', (e) => { e.preventDefault(); userName.style.display = 'block'; }); // обрабатываем клик на кнопке "Ок" после введения имени именинника nameBtn.addEventListener('click', function() { userName.style.display = 'none'; let str = this.previousElementSibling.value; if (str.trim() == '') str = 'чувак'; femaleName(str); }); //проверяем, является ли имя женским function femaleName(name) { let regex = new RegExp(/[ая]$/i); regex.test(name.slice(-1)) ? cardTitle.innerHTML = `Дорогая ${name}!` : cardTitle.innerHTML = `Дорогой ${name}!`; } } birthdayCard(); |
В этом коде мы обрабатываем событие клика на кнопке с текстом "Задать имя" и атрибутом id="addName"
, отображая скрытый изначально блок с полем ввода имени именинника и кнопкой "Ок" с атрибутом id="nameBtn"
. Когда пользователь щелкает по этой кнопке, но при этом ничего не вводит или вводит пробелы, мы проверяем, является ли пустой очищенная методом trim()
строка, и выводим вместо имени посетителя слово "чувак"
:). Можете заменить его на любой другое в собственном коде.
Если же пользователь ввел не пустую строку, мы проверяем в функции femaleName(name), является ли это имя женским, подразумевая, что большинство женских имен заканчиваются на букву "а" или "я". Именно они указаны в регулярном выражении new RegExp(/[ая]$/i)
.
Не обошлось, конечно, без казусов. Если вы введете, например, "Вася" или "Толя", то получите "Дорогая Вася" или "Дорогая Толя" ))), поэтому мужские имена лучше вводить полностью.
Наш пример изменился. Нажмите на кнопку-ссылку внизу - и увидите форму для ввода имени именинника:
Добавляем переход по ссылке с параметром в виде имени с помощью свойства location.search
Возможно, вы задумались о том, что неплохо бы такую открытку послать имениннику в день рождения, отправив ему ссылку в письме или в любом из мессенжеров (Вайбер, Telegram, WhatsApp). И в этом случае уж конечно не стоит отображать кнопку для ввода имени. А сам блок с полем ввода изначально скрыт в стилях за счет свойства display: none
.
Воспользуемся для трансформации кода свойством глобального объекта Location search
, которое возвращает часть адреса страницы после знака ?. Т.е. в ссылке вида http://mysite.com/card.html?Наташа в свойстве location.search
мы получим строку ?Наташа
. И эту строку нам нужно будет обработать, убрав из нее знак вопроса и подставив вместо имени пользователя в заголовок нашей открытки. Для этого нам обязательно надо проверить, а существует ли строка в этом свойстве - в этом случае длина строки locationName.length
будет больше ноля. И если это так, то мы скрываем кнопку-ссылку с текстом "Задать имя" и изменяем заголовок, воспользовавшись функцией femaleName(name)
:
1 2 3 4 5 6 7 8 9 |
function birthdayCard() { ...; //весь код, что был ранее const locationName = decodeURIComponent(location.search.slice(1)); console.log(locationName); // посмотрите, что будет выведено if (locationName.length) { addName.style.display = 'none'; femaleName(locationName); } } |
В этом коде мы используем метод decodeURIComponent()
для того, чтобы декодировать кириллические символы, которые браузер преобразует в формат Unicode. Без этого, например, имя Николай будет выглядеть, как "B8%D0%BA%D0%BE%D0%BB%D0%B0". Не слишком понятно, не так ли?
Следующий пример отобразит вам открытку с именем Наташа:
Заметили, что внизу отсутствует кнопка-ссылка "Задать имя"?
И это еще не все. На основе этого кода мы можем сформировать ссылку, которую, собственно, и будем отсылать друзьям-знакомым. Ниже приведен код, который сначала формирует запрос с помощью диалогового окна prompt()
(можно заменить полями формы), затем формирует ссылку нужного вида и копирует эту ссылку в буфер обмена.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<a href="#" onclick="showLink(this)">Задать имя именинника</a> <script> function showLink(elem) { let name = prompt("Введите имя именинника", "Николай"); if(name.trim().length<2){ alert('Нужно ввести хотя бы 2 символа\nИмя, например.'); return false } // задайте путь к своему сайту let link = "http://mysite.com/card.html?"+name; console.log(link); let tmp = document.createElement('input'); document.body.append(tmp); tmp.value = link; tmp.select(); document.execCommand("copy"); tmp.remove(); elem.href = link; } </script> |
Попробуйте сами. После ввода имени ссылка должна скопироваться в буфер обмена и ее сразу можно высылать имениннику.
Нажмите на кнопку для получения ссылки с нужным вам именем.
Вот такой получился длинный пример, в котором, кроме обработки события onmousemove, мы сделали очень много вещей.