Разработка


Вывод блока при первом посещении сайта

$(document).ready(function() {
    var isshow = localStorage.getItem('isshow');
    if (isshow== null) {
        localStorage.setItem('isshow', 1);

        // Находим нужный блок с display: none; и показываем его, моем случае div с классом 'cookie'
      $('.cookie').show();
}
});

//close the warning about the use of cookies
$(document).on('click', '#cookieAccept', function () {
    $('.cookie').slideUp('slow');
});

//open popup window cookies description
$(document).on('click', '#openCookieDescription', function (er) {
    er.preventDefault();
    $('.cookie-description').fadeIn('slow').css('display','flex');
});

//close popup window cookies description
$(document).on('click', '#closeCookieDescription', function () {
    $('.cookie-description').fadeOut('slow');
});

HTML

<div class="cookie" style="display:none;">
    <div class="container">
        <div class="row">
            <div class="col-lg-8 offset-lg-1">
                <div class="cookie-text">Мы используем <a href="#cookie" id="openCookieDescription">Cookie</a> (файлы с данными о прошлых посещениях сайта) для персонализации сервисов и удобства пользователей. Вы можете запретить сохранение cookie в настройках своего браузера.</div>
            </div>
            <div class="col-lg-2 mt-3">
                <button class="btn cookie-btn" id="cookieAccept">OK</button>
            </div>
        </div>
    </div>
</div>

Вывод видео с YouTube

.video {
	position: relative;
	width: 100%;
	height: 0;
	padding-top: 56.25%;
	overflow: hidden;
	-webkit-border-radius: 0.5rem;
	        border-radius: 0.5rem;
}

@media (min-width: 801px) {
	.video {
		height: 474px;
		padding-top: 0;
	}
}

.video_responsive {
	height: 0;
	padding-top: 56.25%;
}
.video__play-button {
	position: absolute;
	top: 50%;
	left: 50%;
	z-index: 5;
	padding: 0;
	margin: 0;
	background: none;
	border: none;
    width: 100px;
    height: 100px;
	-webkit-transform: translate(-50%, -50%);
	    -ms-transform: translate(-50%, -50%);
	        transform: translate(-50%, -50%);          
}

.video__play-button::before {
	position: absolute;
	top: 50%;
	left: 50%;
	z-index: 1;
	width: 100px;
	height: 80px;
	content: "";
	background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-35.20005 -41.33325 305.0671 247.9995'%3E%3Cpath d='M229.763 25.817c-2.699-10.162-10.65-18.165-20.748-20.881C190.716 0 117.333 0 117.333 0S43.951 0 25.651 4.936C15.553 7.652 7.6 15.655 4.903 25.817 0 44.236 0 82.667 0 82.667s0 38.429 4.903 56.85C7.6 149.68 15.553 157.681 25.65 160.4c18.3 4.934 91.682 4.934 91.682 4.934s73.383 0 91.682-4.934c10.098-2.718 18.049-10.72 20.748-20.882 4.904-18.421 4.904-56.85 4.904-56.85s0-38.431-4.904-56.85' fill='%23EB3D1D'/%3E%3Cpath d='M93.333 117.559l61.333-34.89-61.333-34.894z' fill='%23fff'/%3E%3C/svg%3E") center center no-repeat;
	-webkit-transition: all 0.25s ease-in-out;
	transition: all 0.25s ease-in-out;
	-webkit-transform: translate(-50%, -50%);
	    -ms-transform: translate(-50%, -50%);
	        transform: translate(-50%, -50%);
}

.video__play-button:hover{
  opacity: .8;
}

.video__missing {
	position: absolute;
	top: 0;
	left: 0;
	z-index: 5;
	display: -webkit-box;
	display: -webkit-flex;
	display: -ms-flexbox;
	display: flex;
	-webkit-box-orient: vertical;
	-webkit-box-direction: normal;
	-webkit-flex-direction: column;
	    -ms-flex-direction: column;
	        flex-direction: column;
	-webkit-box-align: center;
	-webkit-align-items: center;
	    -ms-flex-align: center;
	        align-items: center;
	-webkit-box-pack: center;
	-webkit-justify-content: center;
	    -ms-flex-pack: center;
	        justify-content: center;
	width: 100%;
	height: 100%;
	color: var(--vzlet-neutral-60);
}
.video__missing .h2 {
	margin-bottom: 0;
	color: var(--vzlet-primary-main);
}
.video__image, .video__thumbnail {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
}
.video__image img, .video__thumbnail img {
	width: 100%;
	height: 100%;
	-o-object-fit: cover;
	   object-fit: cover;
}
.video iframe {
	position: absolute;
	top: 0;
	left: 0;
	z-index: 10;
	width: 100%;
	height: 100%;
	border-width: 0;
	outline-width: 0;
}
document.addEventListener("DOMContentLoaded", () => { 

  function youtube_parser(url){
    // let regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;
    let regExp = /^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/|shorts\/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*/;
    let match = url.match(regExp);
    return (match&&match[1].length==11)? match[1] : false;
  }
  
  function youtubeVideo() {
    let youtubeVideos = document.querySelectorAll('.js-youtube-video');
    if (youtubeVideos.length > 0) {
      youtubeVideos.forEach(function(video) {
    
        // Создаём кнопку, клик по которой будет грузит iframe с видео и запускать его
        let button = document.createElement('button');
        button.classList.add('video__play-button');
      
        // Data-атрибуты из блока с видео
        let source = video.dataset.src;
        let image = video.dataset.image;
    
        // Если есть ссылка на видео
        if (source) {
          
          // Добавляем кнопку, которую создали ранее
          video.insertAdjacentElement('afterbegin', button);
    
          // Если есть картинка
          if (image) {
            // Грузим своё превью
            video.insertAdjacentHTML('beforeend', '<div class="video__image"><img src="' + image + '" alt="Видео-превью"></div>');
            // Удаляем data-атрибут
            video.removeAttribute('data-image');
          } else {
            // Грузим превью ютуба
            video.insertAdjacentHTML('beforeend', '<div class="video__thumbnail"><img src="https://i.ytimg.com/vi/' + youtube_parser(source) + '/maxresdefault.jpg" alt="Видео-превью"></div>');
          }

          // По клику грузим iframe с youtube и запускаем видео
          button.addEventListener('click', function(e) {
            e.preventDefault();
            video.insertAdjacentHTML('beforeend', '<iframe src="https://www.youtube.com/embed/' + youtube_parser(source) + '?rel=0&autoplay=1" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>');
          });
    
        } else {
          // Показываем сообщение о том, что нет видео
          video.insertAdjacentHTML('beforeend', '<div class="video__missing"><div class="h2">Видео пропало</div><div>Простите за неудобство</div></div>');
        }
      });
    }
  }
  

  youtubeVideo();
});
<div class="video js-youtube-video" data-src="https://youtu.be/2VTyRYsTbZw" data-image="">
    <button class="video__play-button"></button>
    <div class="video__thumbnail">
        <img src="https://i.ytimg.com/vi/2VTyRYsTbZw/maxresdefault.jpg" alt="Видео-превью">
    </div>
</div>

Отложенная загрузка Яндекс метрики

(function () {
    'use strict';

    // Флаг, что Метрика уже загрузилась.
    var loadedMetrica = false,
        // Ваш идентификатор сайта в Яндекс.Метрика.
        metricaId = 123456789,
        // Переменная для хранения таймера.
        timerId;

    // Для бота Яндекса грузим Метрику сразу без "отложки",
    // чтобы в панели Метрики были зелёные кружочки
    // при проверке корректности установки счётчика.
    if ( navigator.userAgent.indexOf( 'YandexMetrika' ) > -1 ) {
        loadMetrica();
    } else {
        // Подключаем Метрику, если юзер начал скроллить.
        window.addEventListener( 'scroll', loadMetrica, {passive: true} );

        // Подключаем Метрику, если юзер коснулся экрана.
        window.addEventListener( 'touchstart', loadMetrica );

        // Подключаем Метрику, если юзер дернул мышкой.
        document.addEventListener( 'mouseenter', loadMetrica );

        // Подключаем Метрику, если юзер кликнул мышкой.
        document.addEventListener( 'click', loadMetrica );

        // Подключаем Метрику при полной загрузке DOM дерева,
        // с "отложкой" в 1 секунду через setTimeout,
        // если пользователь ничего вообще не делал (фоллбэк).
        document.addEventListener( 'DOMContentLoaded', loadFallback );
    }

    function loadFallback() {
        timerId = setTimeout( loadMetrica, 1000 );
    }

    function loadMetrica( e ) {

        // Пишем отладку в консоль браузера.
        if ( e && e.type ) {
            console.log( e.type );
        } else {
            console.log( 'DOMContentLoaded' );
        }

        // Если флаг загрузки Метрики отмечен,
        // то ничего более не делаем.
        if ( loadedMetrica ) {
            return;
        }

        (function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)}; m[i].l=1*new Date();k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)}) (window, document, "script", "<https://cdn.jsdelivr.net/npm/yandex-metrica-watch/tag.js>", "ym");
        ym( metricaId, "init", { clickmap:true, trackLinks:true, accurateTrackBounce:true });

        // Отмечаем флаг, что Метрика загрузилась,
        // чтобы не загружать её повторно при других
        // событиях пользователя и старте фоллбэка.
        loadedMetrica = true;

        // Очищаем таймер, чтобы избежать лишних утечек памяти.
        clearTimeout( timerId );

        // Отключаем всех наших слушателей от всех событий,
        // чтобы избежать утечек памяти.
        window.removeEventListener( 'scroll', loadMetrica );
        window.removeEventListener( 'touchstart', loadMetrica );
        document.removeEventListener( 'mouseenter', loadMetrica );
        document.removeEventListener( 'click', loadMetrica );
        document.removeEventListener( 'DOMContentLoaded', loadFallback );
    }
} )()

Плавный скролл до элемента на JavaScript

Разработаем следующее: после клика по ссылке будет происходить плавный скролл до элемента на JavaScript. Реализуем это без использования плагинов, сначала при помощи библиотеки jQuery, а затем на чистом JavaScript

Плавный скролл до якоря.

С помощью jQuery.

Для всех ссылок, начинающихся с #.

На чистом JavaScript - метод Element.scrollIntoView().

На чистом JavaScript - метод Window.scrollBy().

Сначала в HTML реализуем обычный «грубый» переход к секции, а затем уже добавим jQuery для создания плавности скролла.

Добавим codeid секциям к которым мы хотим выполнять скролл, а ссылкам атрибут codehref в формате code#name. Решетка - означает идентификатор (id), а name - имя идентификатора.

Наш HTML файл получится примерно такой.

<nav class="scrollto">
    <ul>
        <li><a href="#element1">Ссылка-1</a></li>
        <li><a href="#element2">Ссылка-2</a></li>
        <li><a href="#element3">Ссылка-3</a></li>
    </ul>
</nav>

<section id="element1">Секция-1</section>
<section id="element2">Секция-2</section>
<section id="element3">Секция-3</section>

Атрибут href указывает к какому элементу необходимо осуществить переход.

Плавный скролл с используя jQuery

Теперь добавим плавности с помощью библиотеки jQuery. В js-файле добавьте следующи код.

$('.scrollto a').on('click', function() {

    let href = $(this).attr('href');

    $('html, body').animate({
        scrollTop: $(href).offset().top
    }, {
        duration: 370,   // по умолчанию «400»
        easing: "linear" // по умолчанию «swing»
    });

    return false;
});

Чтобы добавить плавность перехода для необходимого элемента, просто добавьте навигации класс scrollto

Изменить скорость скролла можно поменяв значение duration

Плавный скролл для всех ссылок, начинающихся с

Для этого мы обратимся к селектору атрибута тега a при помощи ^ - что будет означать, что мы выбираем все ссылки, начинающиеся с # (решётки)

$('a[href^="#"').on('click', function() {

    let href = $(this).attr('href');

    $('html, body').animate({
        scrollTop: $(href).offset().top
    });
    return false;
});

Плавный скролл на чистом JavaScript - метод Element.scrollIntoView()

Будем использовать метод scrollIntoView(). Это стандартный нативный метод JavaScript.

У метода scrollIntoView() есть недостаток.

Если у нас будет навигация position: fixed, то нам необходимо добавить отступ сверху на x-пикселей, т.е. высоту навигации.

Для решения данной задачи отлично подойдёт метод Window.scrollBy().

Плавный скролл на чистом JavaScript - метод Window.scrollBy()

Метод Window.scrollBy() имеет параметр top в котором мы укажем количество пикселей, на сколько нам необходимо прокрутить страницу.

От общей высоты документа отнимем высоту навигации и получим необходимое смещение в пикселях по оси Y.

document.querySelectorAll('a[href^="#"').forEach(link => {

    link.addEventListener('click', function(e) {
        e.preventDefault();

        let href = this.getAttribute('href').substring(1);

        const scrollTarget = document.getElementById(href);

        const topOffset = document.querySelector('.scrollto').offsetHeight;
        // const topOffset = 0; // если не нужен отступ сверху
        const elementPosition = scrollTarget.getBoundingClientRect().top;
        const offsetPosition = elementPosition - topOffset;

        window.scrollBy({
            top: offsetPosition,
            behavior: 'smooth'
        });
    });
});

Youtube несколько видео на странице и стоп проигрывания предыдущего видео

Youtube несколько видео на странице. Как сделать остановку предыдущего видео, при запуске следующего?

На сайте расположено на одной странице три видео. При включении нужно чтобы другое видео, если запущено , останавливалось. Как это реализовать?

<div class="mVideos"></div>

<script type="text/javascript">
    // Массив с id видео
    var videos = [{id: "GEPIsgsnAuE"}, {id: "ymXnKNbv5Es"}, {id: "dN_Km7zyDVo"}, {id: "d55fuDZy-q8"}];

    var tag = document.createElement('script');
    var players = [];

    tag.src = "<https://www.youtube.com/iframe_api>";

    var firstScriptTag = document.getElementsByTagName('script')[0];

    firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

    var pVideo = document.querySelector(".mVideos");

    for(var i = 0; videos.length > i; i++) {
        // Создаем дочерние элементы с id
        var newDiv = document.createElement("div");
        newDiv.setAttribute("id", videos[i].id);

        // Добавление элементов видео в родительских контейнер        
        pVideo.appendChild(newDiv);

        item = document.querySelector("#"+videos[i].id).getAttribute("id");
        var player;
        players.push(item);
    }

    function onYouTubeIframeAPIReady() {
        for(var k = 0; players.length > k; k++) {
            players[k] = new YT.Player(players[k], {
                                height: '360',
                                width: '640',
                                videoId: players[k],
                                events: {
                                    'onReady': onPlayerReady,
                                    'onStateChange': onPlayerStateChange
                            }
                        });
        }
    }

    function onPlayerReady(event) {
        event.target.stopVideo();
    }

    function onPlayerStateChange(event) {
        if (event.data == YT.PlayerState.PLAYING) {
                var temp = event.target.getVideoUrl();
                for (var i = 0; i < players.length; i++) {
                        if (players[i].getVideoUrl() != temp) players[i].stopVideo();
                }
        }
    }
</script>

Адаптивное видео (iframe)

<div class="thumb-wrap">
	<iframe width="560" height="315" src="https://www.youtube.com/embed/Y421bWMelqE" frameborder="0" allowfullscreen></iframe>
</div>
.thumb-wrap {
  position: relative;
  padding-bottom: 56.25%; /* задаёт высоту контейнера для 16:9 (если 4:3 — поставьте 75%) */
  height: 0;
  overflow: hidden;
}

.thumb-wrap iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border-width: 0;
  outline-width: 0;
}

Ссылка "Проложить маршрут" сайте

<a href="https://yandex.ru/maps/?rtext=~55.614309,37.484146" target="_blank">
  Проложить маршрут на карте
</a>

Фиксированная шапка при прокрутке

$(function() {
    let header = $('.c-header-site');
    let hederHeight = header.height();
    $(window).scroll(function() {
      if($(this).scrollTop() > 1) {
       header.addClass('header_fixed');
       $('body').css({
          'paddingTop': hederHeight+'px'
       });
      } else {
       header.removeClass('header_fixed');
       $('body').css({
        'paddingTop': 0
       })
      }
    });
});

Вывод ошибок через .htaccess

php_flag display_startup_errors off
php_flag display_errors off
php_flag html_errors off
php_flag log_errors on
php_flag ignore_repeated_errors off
php_flag ignore_repeated_source off
php_flag report_memleaks on
php_flag track_errors on
php_value docref_root 0
php_value docref_ext 0
php_value error_log /home/a/xxxx/site.ru/public_html/PHP_errors.log
php_value error_reporting 2047
php_value log_errors_max_len 0

Полный путь можно узнать через $_SERVER['DOCUMENT_ROOT']