Конфликт JS скриптов

У меня есть два скрипта которые выполняют разный функционал и при подключении обоих, один из них перестает работать.

Первый скрипт custom.js и он отвечает за всю динамику на сайте(движение объектов)

Второй скрипт telega-chat.js отвечает за появление онлайн чата на сайте и весь его функционал. Само появление чата происходит нажатием на кнопку и выполняется скриптом в HTML странице:

<script>
        document.querySelector('.chat')
            .addEventListener('click', e => {
                console.log('Открываем чат');
                new TelegaChat().open()
            })
</script>

При подключении скрипта telega-chat.js, перестает работать функционал скрипта custom.js который отвечает за фиксацию шапки сайта, счетчик(при прокрутке страницы начисляются цифры) и кнопка прокрутки страницы вверх.

Я не силен в разработке и по этому выскажу лишь предположения проблемы. Скорее всего это связано с DOM деревом и переопределением объектов в нем. Как это справить я не знаю. Пытался мучать искусственный интеллект, но ни один не смог мне помочь. Помогите кто знает. Могу лишь сказать, что я пытался завернуть скрипт telega-chat.js внутрь функции, но это не помогло.

Первый скрипт - custom.js

(function() {

    "use strict";
  
    var app = {
        
        init: function() {

            //=== Main visible ===\\
            this.mainVisible();

            //=== lazy loading effect ===\\
            this.lazyLoading();

            this.setUpListeners();

            //=== Custom scripts ===\\
            this.headerFixed.init();
            this.btnHover();
            this.appendMfBg();
            this.appendBtnTop();
            this.formingHrefTel();
            this.contentTable();
            this.counters.init();

            //=== Plugins ===\\
            this.device();

        },
        
        setUpListeners: function() {

            //=== Ripple effect for buttons ===\\
            $(".ripple").on("click", this.btnRipple);

            //=== Mobile/tablet main menu ===\\
            // Main menu toogle \\
            $(".main-mnu-btn").on("click", this.mainMenu.toggle);
            // Main menu close not on this element \\
            $(document).on("click", this.mainMenu.closeNotEl);

            //=== Tab ===\\
            $(".tabs-nav li").on("click", this.tab);

            //=== Accordion ===\\
            $(".accordion-trigger").on("click", this.accordion);

            //=== Button top ===\\
            $(document).on("click", '.btn-top', this.btnTop);
            $(window).on("scroll", this.btnTopScroll);

            $(document).on("click", '.scroll-to', this.scrollTo);
            
        },

        //=== Body visible ===\\
        mainVisible: function() {

            $(".main").addClass("main-visible");

        },

        appendMfBg: function() {

            $("body").append('<div class="mf-bg"></div>');

        },

        appendBtnTop: function() {

            $("body").append('<div class="btn-top"><svg class="btn-icon-right" viewBox="0 0 13 9" width="13" height="9"><use xlink:href="assets/img/sprite.svg#arrow-right"></use></svg></div>');

        },

        btnTop: function() {
            
            $('html, body').animate({scrollTop: 0}, 1000, function() {
                $(this).removeClass("active");
            });

        },

        btnTopScroll: function() {
            
            var btnTop = $('.btn-top');
            
            if ($(this).scrollTop() > 700) {

                btnTop.addClass("active");

            } else {

                btnTop.removeClass("active");
                
            }

        },

        scrollTo: function() {

            $('html, body').animate({scrollTop: $($(this).attr('data-scroll-to')).position().top}, 1000);

        },

        //=== Header fixed ===\\
        headerFixed: {

            init: function() {

                if( $('.header-fixed').length ) {
    
                    $(window).on("load resize scroll", app.headerFixed.handler);
    
                }
                
            },
    
            IS_FIXED: false,
    
            handler: function() {
    
                var header = $('.header-fixed');
                var height = header.outerHeight();
                var offsetTop = header.offset().top;
                var scrollTop = $(this).scrollTop();
    
                var headerStatic = $(".header-fixed-static");
                if(headerStatic.length) { 
                    offsetTop = headerStatic.offset().top;
                    headerStatic.css("height", height);
                }
    
                if(scrollTop >= offsetTop) {
                    if(!app.headerFixed.IS_FIXED) {
                        header.addClass("fixed");
                        header.after('<div class="header-fixed-static" style="height:' + height + 'px"></div>');
                    }
                    app.headerFixed.IS_FIXED = true;
                } else {
                    if(app.headerFixed.IS_FIXED) {
                        header.removeClass("fixed");
                        headerStatic.remove();
                    }
                    app.headerFixed.IS_FIXED = false;
                }
    
            }

        },

        //=== Tab ===\\
        tab: function() {

            var _this = $(this),
                index = _this.index(),
                tabs = _this.closest(".tabs"),
                items = tabs.find(".tabs-item");

            if (!_this.hasClass("active")) {

                items
                    .eq(index)
                    .add(_this)
                    .addClass("active")
                    .siblings()
                    .removeClass("active");
            
            }

        },

        //=== Accordion ===\\
        accordion: function(e) {

            e.originalEvent.preventDefault();

            var _this = $(this),
                item = _this.closest(".accordion-item"),
                container = _this.closest(".accordion"),
                items = container.find(".accordion-item"),
                content = item.find(".accordion-content"),
                otherContents = container.find(".accordion-content"),
                duration = 300;

            if (!item.hasClass("active")) {
                items.removeClass("active");
                item.addClass("active");
                otherContents.stop(true, true).slideUp(duration);
                content.stop(true, true).slideDown(duration);
            } else {
                content.stop(true, true).slideUp(duration);
                item.removeClass("active");
            }

        },

        //=== Mobile/tablet main menu ===\\
        mainMenu: {

            toggle: function() {

                var _this = $(this),
                    _body = $("body"),
                    headerHeight = _this.closest(".header").outerHeight(),
                    headerOffsetTop = _this.closest(".header").offset().top,
                    mnu = $(".mmm"),
                    headeFixedOffsetTop = $(".header-fixed").offset().top;

                if(headeFixedOffsetTop <= headerOffsetTop) {
                    $("html").scrollTop(headeFixedOffsetTop + 1);
                }
                    
                mnu.css("padding-top", headerHeight);
                $(this).toggleClass("active");
                
                _body.toggleClass("mmm-open").scrollTop(headeFixedOffsetTop);
                    
                if(_body.hasClass("mmm-open")) {
                    $(".mf-bg").addClass("visible mm");
                } else {
                    $(".mf-bg").removeClass("visible mm");
                }
    
            },

            closeNotEl: function(e) {

                if($("body").hasClass("mmm-open")) {
                    if ($(e.originalEvent.target).closest(".mmm, .main-mnu-btn").length) return;
                    $("body").removeClass("mmm-open");
                    $(".main-mnu-btn").removeClass("active");
                    $(".mf-bg").removeClass("visible mm");
                    e.originalEvent.stopPropagation();
                }
    
            }

        },

        //=== Ripple effect for buttons ===\\
        btnRipple: function(e) {
            
            var _this = $(this),
                offset = $(this).offset(),
                positionX = e.originalEvent.pageX - offset.left,
                positionY = e.originalEvent.pageY - offset.top;
            _this.append("<div class='ripple-effect'>");
            _this
                .find(".ripple-effect")
                .css({
                    left: positionX,
                    top: positionY
                })
                .animate({
                    opacity: 0
                }, 1500, function() {
                    $(this).remove();
                });

        },

        btnHover: function() {

            var btns = document.querySelectorAll(".btn, .el-ripple"),
                btn = [];

            btns.forEach(function(element, index) {

                var span = document.createElement("span"); 
                span.className = "el-ripple-circle";
                element.appendChild(span);

                // If The span element for this element does not exist in the array, add it.
                if (!btn[index])
                btn[index] = element.querySelector(".el-ripple-circle");

                element.addEventListener("mouseenter", function(e) {    
                    btnHandler(element, index, e);          
                });

                element.addEventListener("mouseleave", function(e) {
                    btnHandler(element, index, e);
                });
                
            });

            const btnHandler = function(element, index, e) {

                let offset = element.getBoundingClientRect(),
                    left = e.pageX - offset.left - window.scrollX,
                    top = e.pageY - offset.top - window.scrollY;

                btn[index].style.left = left + "px";
                btn[index].style.top = top + "px";

            }

        },

        //=== Forming href for phone ===\\
        formingHrefTel: function() {

            var linkAll = $('.formingHrefTel'),
                joinNumbToStringTel = 'tel:';

            $.each(linkAll, function () {
                var _this = $(this),
                    linkValue = _this.text(),
                    arrayString = linkValue.split("");

                for (var i = 0; i < arrayString.length; i++) {
                    var thisNunb = app.isNumber(arrayString[i]);
                    if (thisNunb === true || (arrayString[i] === "+" && i === 0)) {
                        joinNumbToStringTel += arrayString[i];
                    }
                }

                _this.attr("href", function () {
                    return joinNumbToStringTel;
                });
                joinNumbToStringTel = 'tel:'

            });

        },

        isNumber: function(n) {

            return !isNaN(parseFloat(n)) && isFinite(n);

        },
        
        //=== Content table responsive ===\\
        contentTable: function() {

            var contentTable = $(".content");
            if(contentTable.length) {
                
                $.each(contentTable.find("table"), function() {
                    $(this).wrap("<div class='table-responsive-outer'></div>").wrap("<div class='table-responsive'></div>");
                });
                
            }

        },

        //=== Counters ===\\
        counters: {

            init: function() {

                $(window).on("scroll load resize", function () {

                    app.counters.spincrement();
    
                });

            },

            spincrement: function() {

                var counters = $(".spincrement-container");
    
                if(counters.length) {
    
                    jQuery.each(counters, function() {
    
                        var _this = $(this);
        
                        if ( $(window).scrollTop() > _this.offset().top - ($(window).height() * 0.85) && !_this.hasClass("animated") ) {
        
                            _this.addClass("animated");
        
                            _this.find('.spincrement').spincrement({
                                duration: 1500,
                                leeway: 10,
                                thousandSeparator: '',
                                decimalPoint: ''
                            });
                            
                        }
        
                    });
    
                }
    
            },

        },

        //=== Plugins ===\\
        lazyLoading: function() {

            var observer = lozad('.lazy');
            observer.observe();

        },

        device: function() {

            if( (device.mobile() || device.tablet()) && device.ios() ) {
                var tempCSS = $('a').css('-webkit-tap-highlight-color');
                $('main, .main-inner').css('cursor', 'pointer')
                         .css('-webkit-tap-highlight-color', 'rgba(0, 0, 0, 0)');
                $('a').css('-webkit-tap-highlight-color', tempCSS);
            }

        },
        
    }
 
    app.init();
 
}());

Второй скрипт telega-chat.js

window.$ = (el) => {
  if (document.querySelector(el) !== null) return document.querySelector(el)
  else console.warn(`${el} не найден в дом дереве`);
};

window.$$ = (el) => {
  if (document.querySelectorAll(el) !== null) return document.querySelectorAll(el)
};

//Фунцкия воспроизведения звуков
window.soundPush = (url) => {
  let audio = new Audio(); // Создаём новый элемент Audio
  audio.src = url; // Указываем путь к звуку "клика"
  audio.autoplay = true; // Автоматически запускаем
  audio.volume = 0.7
  $('body').appendChild(audio)
  audio.addEventListener("ended", e => audio.remove())
  return url
}

function getRandomInt(max) {
  return Math.floor(Math.random() * max);
}

let timeNow = new Date().toLocaleTimeString();
const token = ``; // Получаем тут https://t.me/BotFather
const chatId = ``;  //получаем при вызове https://api.telegram.org/bot/getupdates в браузере


let startChat = false
let lastMessId, FirstMessId, newMessId, checkReply, Timer, count;
let idStart = getRandomInt(999)


// Имя менагера
const manager = 'Кристина'

let tpl = `<div class="chat__wrap">
    <div class="chat__title">Онлайн-чат
    <div class="btm__close chat__close">&times;</div>
    </div>
    <div class="chat__body">
    <div class="chat__body__item chat__body__item__manager">
    <span class="chat__body__item__user">${manager}</span>
    <span class="chat__body__item__text">Добрый день. Какой у вас вопрос?</span>
    <i class="chat__body__item__time">${timeNow}</i>
    </div>
    </div>
    <div class="chat__input">
        <div class="chat__input__message">
            <div class="texta">
               <textarea rows="1" wrap="on" type="text" class="chat__main__input" aria-label="Напишите сообщение" placeholder="Напишите сообщение" required ></textarea>
            </div>
        </div>
        <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" class="bi bi-send chat__input__submit" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><path d="M88,134.9,224.1,36.6h0a7.8,7.8,0,0,0-6.2-.2L33.3,108.9c-7.4,2.9-6.4,13.7,1.4,15.3Z" opacity="0.2"/><path d="M132.9,174.4l-31.2,31.2A8,8,0,0,1,88,200V134.9Z" opacity="0.2"/><path d="M88,134.9,177.9,214a8,8,0,0,0,13.1-4.2L228.6,45.6a8,8,0,0,0-10.7-9.2L33.3,108.9c-7.4,2.9-6.4,13.7,1.4,15.3Z" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="88" y1="134.9" x2="224.1" y2="36.6" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M132.9,174.4l-31.2,31.2A8,8,0,0,1,88,200V134.9" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></svg>
        </div>
    
    </div>`;


class TelegaChat {
  open() {

    this.getIp()

    if (window.innerWidth < 768) $("body").classList.add('overflow__hidden')

    if (!$(".chat__wrap")) $("body").insertAdjacentHTML("afterbegin", tpl);

    let store = localStorage.getItem("historyMessages");

    if (store !== null) {
      $(".chat__body").innerHTML = store;
    }

    $(".chat__main__input").onkeypress = (e) => {
      if (e.key === `Enter`) this.submit();
      if (e.target.value !== '') $(".chat__main__input").classList.remove('validate__error')
    };

    $(".chat__input__submit").onclick = () => this.submit();

    $(".chat__close").onclick = () => this.close()

    $(".chat__body").scrollTop = 100000;

    $(".chat__wrap").classList.add("open");

    setTimeout(() => {
      $('.chat__main__input').focus()
    }, 1000);


    axios.get(`https://api.telegram.org/bot${token}/getupdates`)
    .then((r) => {
      lastMessId = r.data.result[r.data.result.length - 1].message.message_id;
      FirstMessId = lastMessId
    })

    this.deleteItem()
  }

  close() {
    clearInterval(Timer)
    $(".chat__wrap").classList.remove("open");
    if (window.innerWidth < 768) $("body").classList.remove('overflow__hidden')
  }

  deleteItem() {
    $$('.chat__body__item').forEach(el => {
      if (el.querySelector('.chat__body__item__delete')) el.querySelector('.chat__body__item__delete').onclick = () => {
        el.remove()
        localStorage.setItem("historyMessages", $(".chat__body").innerHTML);
      }
    });
  }

  getIp() {
    axios.get(`https://fixdevice.pro/get-ip`)
    .then(r => {
      if (r.data.length > 8 && r.data != 'undefined') idStart = r.data
    })
  }

  submit() {
    timeNow = new Date().toLocaleTimeString();
    let val = $(".chat__main__input").value;
    if (val !== ``) {
      $('.chat__main__input').classList.remove('validate__error')
      let tplItemClient = `<div class="chat__body__item chat__body__item__client">
        <span class="chat__body__item__user">Вы</span>
        <span class="chat__body__item__text">${val}</span>
        <i class="chat__body__item__time">${timeNow}</i></div>`;

      $(".chat__body").innerHTML += tplItemClient;

      $(".chat__body").scrollTop = 100000;

      axios.get(
        `https://api.telegram.org/bot${token}/sendMessage?chat_id=${chatId}&text=USER:${idStart}
            ${val}`
      );

      //soundPush("/sound/set-whatsapp.mp3");
      localStorage.setItem("historyMessages", $(".chat__body").innerHTML);
      setTimeout(() =>$(".chat__main__input").value = ``.trim(), 0);
    
    } else {
      alert(`Введите текст`)
    }

    this.deleteItem()
    this.startUpdate()

    $(".chat__main__input").value = ``

  }

  startUpdate(){
    Timer = setInterval(() => this.checkResponse(), 3000);
  }

  stopUpdate(){
    clearInterval(Timer)
  }

  checkResponse() {
    count++
    if (count > 120 && lastMessId === FirstMessId) this.stopUpdate()

    axios
      .get(`https://api.telegram.org/bot${token}/getupdates`)
      .then((r) => {

        let resLastMess = r.data.result[r.data.result.length - 1].message
        if (resLastMess.reply_to_message !== undefined) checkReply = resLastMess.reply_to_message.text.includes(idStart)
        else checkReply = false

        newMessId = resLastMess.message_id;

        // console.log(FirstMessId, lastMessId , newMessId, checkReply);

        if (newMessId > lastMessId && checkReply) {

          // console.log(1);

          $(".chat__wrap").classList.add("open");

          let Text = r.data.result[r.data.result.length - 1].message.text;

          let tplItemMenager = `<div class="chat__body__item chat__body__item__manager">
              <span class="chat__body__item__user">${manager}</span>
                <span class="chat__body__item__text">${Text}</span>
                <i class="chat__body__item__time">${timeNow}</i></div>`;

          $(".chat__body").innerHTML += tplItemMenager;

          this.deleteItem()

          // soundPush("/sound/get-whatsapp.mp3");

          localStorage.setItem("historyMessages", $(".chat__body").innerHTML);

          $(".chat__body").scrollTop = 100000;

          lastMessId = newMessId

        }
      })
  }
}


// Если нужно отправлять сообщения повторно 
if (localStorage.getItem("historyMessages")) {
  axios.get(`https://api.telegram.org/bot${token}/getupdates`)
    .then((r) => {
      lastMessId = r.data.result[r.data.result.length - 1].message.message_id;
      FirstMessId = lastMessId
      // localStorage.setItem("historyMessages", $(".chat__body").innerHTML);
    })
  new TelegaChat().open()
    $(".chat__wrap").classList.remove("open");
  new TelegaChat().startUpdate()
}


Ответы (1 шт):

Автор решения: ksa

У меня есть два скрипта которые выполняют разный функционал и при подключении обоих, один из них перестает работать.

Как минимум дело в переопределении переменной $. Для первого скрипта это объект jQuery.

Пробуй модернизировать его таким образом.

(function($){
   // тут его содержимое не меняется
})(jQuery)

Вот работающий пример

(function($){
  $('button').on('click', _ => alert('$ все еще работает'))
})(jQuery)

window.$ = _ => console.log('$ сломан')
$()
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<button>Тест</button>

→ Ссылка