Von jQuery zu JavaScript – So gelingt der Umstieg

Von jQuery zu JavaScript – So gelingt der Umstieg Thumbnail
Veröffentlicht am 12. Juni 2020

Von jQuery auf JavaScript umsteigen bietet einige Vorteile. Neben dem Entfernen von totem Code, kannst Du ganz nebenbei auch Deine Website Geschwindigkeit für SEO erhöhen.

Anzeige

Du hast Dich schon mit einem Umstieg von jQuery auf reines JavaScript (auch Vanilla JS genannt) beschäftigt, sonst wärst Du vermutlich nicht hier. Das ist schon mal gut. Auch ich stand vor dieser Entscheidung, deshalb versuche ich Dir beim Umstieg zu helfen und zeige Dir, wieso es sich lohnt und wie Du vorgehen kannst.

Ich hatte die Hoffnung, dass es online eine Art „jQuery zu JavaScript Konverter“ oder Ähnliches gibt. Doch ich wurde eines besseren belehrt.

Wenn Du also den Umstieg wirklich durchziehen möchtest, musst Du das manuell vornehmen. Aber ich helfe Dir, damit der Umstieg gelingt.

Weiter unten findest Du eine Liste mit 1:1 Konvertierungen von jQuery zu Vanilla JavaScript.

SEO verbessern durch Vanilla JavaScript?

Klingt erstmal komisch, aber es ist was dran. Ich bin ständig dabei, diese Seite und die Artikel zu optimieren. Dabei ist für mich – und auch für Suchmaschinen – die Ladegeschwindigkeit der Website eine wichtige Kennzahl.

Ich nutze gerne web.dev Measure oder PageSpeed Insights zum Testen. Im detaillierten Report bekommt man eine genaue Auflistung aller Probleme, darunter auch die Ladegeschwindigkeit.

Anzeige

Bei der Ausführungszeit von JavaScript hatte ich einen zu hohen Wert. Jetzt bin ich damit sehr zufrieden.

JavaScript-Ausführungszeit nach der Umstellung
JavaScript-Ausführungszeit nach der Umstellung

Auch bei Ressourcen die geladen werden tauchte zusätzlich meine jQuery Datei auf. Und wenn Du hier schaust, gehört die jQuery Datei mit 11KB schon zu einer der größeren Dateien – trotz minified.

Ressourcen, die das Rendering blockieren, nach der Umstellung
Ressourcen, die das Rendering blockieren, nach der Umstellung

Nicht falsch verstehen, ich liebe jQuery – einfach eine geniale Library. Ich habe schon viele tolle Funktionen, wie einen Reading Position Indicator mit jQuery programmiert.

Aber dennoch musste ich das von dieser Seite verbannen – für SEO und vielleicht auch als kleine Herausforderung sich mehr mit Vanilla JS zu beschäftigen.

Toten Code entfernen

Wenn man schon etwas an der Struktur ändert, kann man die Gelegenheit direkt nutzen, um unnötigen und veralteten Code zu entfernen.

Dazu habe ich mir eine Liste aller Funktionen gemacht (waren insgesamt 11 Stück) und habe jeder Funktion eine Priorität vergeben.

Ich habe mit den wichtigen und essentiellen Funktionen angefangen und in Vanilla JS umgeschrieben.

Schritt für Schritt. Wenn man jede Funktion einzeln übernimmt findet man eventuell Fehler oder Code der gar nicht mehr benötigt wird. Diesen kannst Du direkt löschen.

Anzeige

Dadurch wird Deine neue JavaScript Datei gleichzeitig aufgeräumt und der Übersichtlichkeit kommt es auch noch direkt zur Gute.

jQuery Code konvertieren

Beim Umbau auf Vanilla JS hat mir besonders die Seite youmightnotneedjquery.com geholfen. Dort werden direkte Funktionen in jQuery und JavaScript verglichen. Ich hoffe, dass Du mit Hilfe meiner und dieser Seite auch den Umstieg so problemlos hinbekommen kannst.

Jetzt kommt die angekündigte Liste, mit direkten Übersetzungen, um jQuery zu Vanilla JS zu konvertieren.

Diese Liste besteht aus den Funktionen, die ich für den Umstieg auf dieser verwendet habe, teilweise gibt es Überschneidungen mit Funktionen von der genannten Seite.

1:1 jQuery zu JavaScript Übersetzungen

Document Ready Funktion

Die Funktion wird aufgerufen, wenn Die Seite geladen ist. Damit blockiert die Ausführung von JavaScript nicht das Laden der Seite.

// with jQuery
$(function() {
  /* ... */
  });


// Vanilla JS
function ready(fn) {
  if (document.readyState != 'loading'){
    fn();
  } else {
    document.addEventListener('DOMContentLoaded', fn);
  }
  }
ready(() => {
  /* ... */
  });

Elemente selektieren

Der größte Unterschied beim Selektieren von Elementen ist, dass man in reinem JavaScript eine Schleife erstellen muss, falls es mehrere Elemente gibt. Bei jQuery kann man z.B. Events über den Selektor registrieren und es gilt für alle. Genaueres im Abschnitt Event Handling.

// with jQuery
// multiple elements
let buttons = $('button.red-btn');

// one element
let button = $('button.green-btn');


// Vanilla JS
// multiple elements
let buttons = document.querySelectorAll('button.red-btn');

// one element
let button = document.querySelector('button.green-btn');

Mit parentNode bekommst Du das Elternelement. Du kannst die Anweisung auch aneinander reihen, um Elemente noch weiter oben im DOM zu bekommen – also parentNode.parentNode.

Anzeige
// with jQuery
let foobarParent = $('#foobar-container').parent();


// Vanilla JS
let foobarParent = document.querySelector('#foobar-container').parentNode;

Event Handling

Beim Event Handling musst Du schaue, ob Du ein oder mehrere Elemente hast. JQuery ist das egal, es registriert einfach das Event. Für beide Situationen ist hier ein Beispiel.

// with jQuery
$('.link').click(function() {
  /* ... */
  });


// Vanilla JS
// one element
document.querySelector('#link').addEventListener('click', event => {
	/* ... */
	});

// more elements
document.querySelectorAll('.link').forEach(link => {
  link.addEventListener('click', event => {
  	/* ... */
  });
  });

Zum Deregistrieren von Events ist in Vanilla JS die eigentliche Event Callback Funktion notwendig. Wenn Du also ein Event registrierst, solltest Du dieses in einer eigenen Callback Funktion anlegen.

// with jQuery
$('#foobar').off('click');


// Vanilla JS
document.getElementById('foobar').removeEventListener('click', clickEvent);
function clickEvent(event) { }

Aktionen auf Elementen durchführen

Um show() und hide() zu erreichen, ändern wir einfach die CSS Eigenschaft display entsprechend.

// with jQuery
$('.foobar').show();


// Vanilla JS
document.querySelectorAll('.foobar').forEach(element => {
  element.style.display = 'block';
  });
// with jQuery
$('.foobar').hide();


// Vanilla JS
document.querySelectorAll('.foobar').forEach(element => {
  element.style.display = 'none';
  });

Attribute von Elementen abfragen und verändern

Die Abfrage und das Handling der Klassen funktioniert genauso einfach wie mit jQuery. Lediglich die Schreibweise ist ein wenig anders. Eine toggleClass() Funktion könntest Du Dir – falls benötigt – auch ganz einfach selber programmieren.

// with jQuery
if($('.foo').hasClass('bar')) {
  /* ... */
  }


// Vanilla JS
if(document.querySelector('.foo').classList.contains('bar')) {
  /* ... */
  }
// with jQuery
$('.foo').addClass('bar');


// Vanilla JS
document.querySelector('.foo').classList.add('bar');
// with jQuery
$('.foo').removeClass('bar');


// Vanilla JS
document.querySelector('.foo').classList.remove('bar');

Auch die Abfrage von anderen Attributen ist recht ähnlich. Beachte, dass manchmal die Ausgabe anders ist, als bei der jQuery Funktion.

// with jQuery
console.log($('.foobar').attr('checked')); // Output: checked/undefined


// Vanilla JS
console.log(document.querySelector('.foobar').checked); // Output: true/false
// with jQuery
$('.foobar').html();
$('.foobar').html('<span>Hello world!</span>');


// Vanilla JS
document.querySelector('.foobar').innerHTML;
document.querySelector('.foobar').innerHTML = '<span>Hello world!</span>';

Offsets und Dimensionen bestimmen

// with jQuery
let offset = $(window).scrollTop();


// Vanilla JS
let offset = window.pageYOffset;
// with jQuery
$(window).width();


// Vanilla JS
parseFloat(getComputedStyle(document.querySelector('html'), null).width.replace("px", ""));
// with jQuery
$('.foobar').width();


// Vanilla JS
document.querySelector('.foobar').offsetWidth;
// with jQuery
$('.foobar').offset().top;


// Vanilla JS
document.querySelector('.foobar').offsetTop;

Styling von Elementen

Bei Styles, die mit einem Bindestrich verbunden werden, kannst Du die Camel-Case Schreibweise verwenden. So wird z.B. aus justify-content justifyContent.

// with jQuery
$('.foobar').css('display', 'flex');
$('.foobar').css('margin-top', '3rem');

let displayProperty = $('.foobar').css('display');


// Vanilla JS
document.querySelector('.foobar').style.display = 'flex';
document.querySelector('.foobar').style.marginTop = '3rem';

let element = document.querySelector('.foobar');
let elementStyle = getComputedStyle(element, null);
let displayProperty = elementStyle.display;

Neue Elemente erstellen

Wenn Du neue Elemente erstellen willst und in ein Element anfügen möchtest, kannst Du das wie folgt machen.

Einzelne Attribute und Klassen müssen einzeln hinzugefügt werden, genauer beschrieben im Abschnitt Attribute von Elementen abfragen und verändern.

Anzeige
// with jQuery
$('.foo').append('<p class="child" id="child-id">bar</p>');


// Vanilla JS
let bar = document.createElement('p');
bar.classList.add('child');
bar.id = 'child-id';
bar.innerHTML = 'bar';
document.querySelector('.foo').appendChild(bar);

So sieht der Umstieg in der Praxis aus

Das ist ein Großteil der Funktionen, die ich bei meinem Umstieg benötigt habe.

Ich möchte Dir aber hier exklusiv die JavaScript Datei dieser Seite. Vor- und nach dem Umstieg zu Vanilla JS.

Vielleicht kannst Du die ein- oder andere Codezeile benutzen. 🙂

Datei vor dem Umstieg (jQuery)

$(function() {
	documentReady();
	});

// WHEN DOCUMENT LOADED
function documentReady() {
	// priavy container on visit begin
	if (
		!getCookie('cookie-state') ||
		getCookie('cookie-state') == undefined ||
		getCookie('cookie-state') == ''
	) {
		$('.privacy-popup').fadeIn(200);
		initCookieClicker();
	}
	$('.open-cookie-menu').click(function() {
		$('.privacy-popup').fadeIn(200);
		initCookieClicker();
		return false;
	});
	
	// set perfect image ratio
	setImageRatio();
	
	let resizeTimeout;
	$(window).resize(function() {
		clearTimeout(resizeTimeout);
		resizeTimeout = setTimeout(function() {
			setImageRatio();
		}, 200);
	});
	
	
	// remove ad containers
	setTimeout(function() {
	
	  var adblockEnabled = false;
	    
	  // add test element and get its styles
	  $('body').append('<div class="adBanner"></div>');
	  var adElement = document.getElementsByClassName('adBanner')[0];
	  var adElementStyle = getComputedStyle(adElement, null);
	  
	  
	  if(adElementStyle.display === 'none') {   // Adblock enabled
	  	$('.cwebdeasy-g-container').remove();
	  	$('.webd-f-container').remove();
	  }
	  
	}, 1500);	
	
	$(window).scroll(function() {
		let offset = $(window).scrollTop();
		if(offset > $('header#masthead').height()) {
			$('header#masthead').addClass('header-box-shadow');
		} else {
			$('header#masthead').removeClass('header-box-shadow');
		}
	});
	
	// show share icon on mobile
	if ($(window).width() < 768) {
		$('.social-icons.vertical .share-icon')
			.show()
			.click(function() {
				if ($('.social-icons.vertical a').is(':visible')) {
					$('.social-icons.vertical a').fadeOut(200);
				} else {
					$('.social-icons.vertical a').fadeIn(200);
				}
			});
	} else {
		setTimeout(function() {
			$('.social-icons.vertical a').fadeIn(400);
		}, 10000);
	}
	
	// collect menu data
	$('.menu-hauptmenue-container .sub-menu .menu-item a, .menu-hauptmenue-en-container .sub-menu .menu-item a').click(function() {
		_paq.push(['trackEvent', 'Desktop Menu', 'Click', 'Open: "' + $(this).html() + '"']);
	});
	
	// collect sidebar click
	$('.menu-sidebar-tutorials-de-container li a, .menu-sidebar-tutorials-en-container li a').click(function() {
		_paq.push(['trackEvent', 'Sidebar Tutorials Menu', 'Click', 'Open: "' + $(this).html() + '"']);
	});
	
	// collect sidebar click
	$('.sidebar-categories a, sidebar-categories a').click(function() {
		_paq.push(['trackEvent', 'Sidebar Categories Menu', 'Click', 'Open: "' + $(this).html() + '"']);
	});
	
	// collect InPost Menu click
	$('.interesting-container li a').click(function() {
		_paq.push(['trackEvent', 'Interesting InPost Menu', 'Click', 'Open: "' + $(this).html() + '"']);
	});
	
	// collect Table of contents click
	$('.table-of-contents li a').click(function() {
		_paq.push(['trackEvent', 'Table of contents', 'Click', 'Jump to: "' + $(this).html() + '"']);
	});
	
	// open mobile menu
	let mobileMenuTimeout;
	$('.mobile-menu-button').click(function() {
		if (mobileMenuTimeout) return false;
		
		clearTimeout(mobileMenuTimeout);
		mobileMenuTimeout = setTimeout(function() {
			mobileMenuTimeout = null;
		}, 200);
		
		if ($(this).hasClass('open')) {
			$(this).removeClass('open');
			$(
				'.menu-hauptmenue-container, .menu-hauptmenue-en-container'
			).slideUp(200);
			$('.mobile-menu-bg-overlay').fadeOut();
		} else {
			$(this).addClass('open');
			$(
				'.menu-hauptmenue-container, .menu-hauptmenue-en-container'
			).slideDown(200);
			$('.mobile-menu-bg-overlay').fadeIn();
			$('.mobile-menu-bg-overlay')
				.off('click')
				.click(function() {
					$('.mobile-menu-button').click();
				});
				
			// open submenu
			if (
				!$('.main-menu .submenu-expand')
					.siblings('.sub-menu')
					.is(':visible')
			) {
				$('.main-menu .submenu-expand')
					// .first()
					.click();
			}
			
			_paq.push(['trackEvent', 'Menu', 'Click', 'Open mobile menu']);
		}
	});
	
	$('.main-menu .submenu-expand').click(function() {
		if ($(window).width() < 1200) {
			$(this)
				.siblings('.sub-menu')
				.slideToggle();
				
			// _paq.push(['trackEvent', 'Menu', 'Click', 'Toggle submenu']);
		}
	});
	
	// minimize code blocks
	$('.wp-block-code, .enlighter-default').each(function() {
		if ($(this).height() >= 450) {
			$(this)
				.children('code')
				.css('height', '450px');
				
			$(this)
				.children('.enlighter')
				.css('display', 'block')
				.css('height', '470px');
				
			$(this)
				.css('height', '545px');
				
			$(this).append(
				'<span class="expand-code btn btn-block btn-sm btn-outline-primary mt-2">' +
					(lang === 'de' ? 'Aufklappen' : 'Expand') +
					'</span>'
			);
		}
	});
	
	// expand code
	$('.expand-code').click(function() {
		if ($(this).hasClass('open')) {
			$(this)
				.siblings('code')
				.css('height', '450px');
			$(this)
				.siblings('.enlighter')
				.css('height', '470px');
			$(this)
				.parent('.enlighter-default')
				.css('height', '545px');
			$(this)
				.removeClass('open')
				.html(lang === 'de' ? 'Aufklappen' : 'Expand');
				
			// _paq.push(['trackEvent', 'Code', 'Click', 'Minified View']);
		} else {
			$(this)
				.siblings('code')
				.css('height', 'auto');
			$(this)
				.siblings('.enlighter')
				.css('height', 'auto');
			$(this)
				.parent('.enlighter-default')
				.css('height', 'auto');
			$(this)
				.addClass('open')
				.html(lang === 'de' ? 'Zuklappen' : 'Collapse');
				
			// _paq.push(['trackEvent', 'Code', 'Click', 'Full View']);
		}
		return false;
	});
	
	// smooth scroll on anchor click
	$('a[href^="#"]').click(function() {
		var elementName = $(this)
			.attr('href')
			.replace('#', '');
			
		if(elementName == undefined || elementName == '') return false;
		
		var element = $('#' + elementName);
		
		if (!element.length) {
			return false;
		}
		
		var elementOffset = element.offset().top - 110;
		
		$('html, body').animate({ scrollTop: elementOffset }, 'slow');
		location.replace('#' + elementName);
		return false;
	});
	
	let sidebarScrollEnabled = true;
	let windowScrollTimeout;
	$(window).scroll(() => {
		clearTimeout(windowScrollTimeout);
		sidebarScrollEnabled = false;
		windowScrollTimeout = setTimeout(() => {
			sidebarScrollEnabled = true;
		}, 1000);
	});
	
	setInterval(() => {
		if($(window).width() > 768 && sidebarScrollEnabled) {
			let offset = $(window).scrollTop();
			
			if($('.single-after-content').offset().top < offset) return false;
			
			let adHeight = 0;
			if($('.cwebdeasy-g-container').length) adHeight = $('.cwebdeasy-g-container').height() + 120;
			
			$('.sidebar-outer-box .js-to-top-container').css('margin-top', (offset - adHeight - 50) + 'px');
		}
	}, 5*1000);
	
	// lightbox
	$('figure > a > picture > img').click(function() {
		if ($(this).attr('src') != '') {
			$('.lightbox .img-container').html(
				'<div class="close">✖</div><img loading="lazy" src="' +
					$(this).attr('src') +
					'"><p>' +
					$(this).attr('alt') +
					'</p>'
			);
			$('.lightbox').fadeIn();
			
			// _paq.push(['trackEvent', 'Lightbox', 'Click', 'Open Lightbox']);
			
			// register close event
			$('.lightbox .close, .lightbox .bg-overlay')
				.off('click')
				.click(function() {
					$('.lightbox').fadeOut();
				});
		}
		return false;
	});
	}

function initCookieClicker() {
	$('.privacy-popup .privacy-container #accept-cookies')
		.off('click')
		.click(function() {
			setCookie('cookie-state', 'all', 7);
			
			// matomo opt in
			_paq.push(['forgetUserOptOut']);
			
			// _paq.push(['trackEvent', 'Cookie Setting', 'Click', 'Accept all']);
			
			$('.privacy-popup').fadeOut(200);
			return false;
		});
	$('.privacy-popup .privacy-container #necessary-cookies')
		.off('click')
		.click(function() {
			setCookie('cookie-state', 'necessary', 7);
			
			// _paq.push([
			// 	'trackEvent',
			// 	'Cookie Setting',
			// 	'Click',
			// 	'Accept necessary'
			// ]);
			
			// matomo opt out
			_paq.push(['optUserOut']);
			
			// remove dark mode option
			// $('.dark-mode-switcher').remove();
			// setCookie('theme', '', 0);
			
			$('.privacy-popup').fadeOut(200);
			return false;
		});
	$('.privacy-popup .privacy-container #show-cookies')
		.off('click')
		.click(function() {
			$('.privacy-popup .more-cookie-infos').fadeToggle();
			return false;
		});
		}

function setImageRatio() {
	// normal preview
	let imageElements = document.querySelectorAll('.post-preview-container .header-container');
	
	if(imageElements.length) {
		let width = imageElements[0].offsetWidth;
		let height = width / 2;
		for(let i = 0; i < imageElements.length; i++) {
			imageElements[i].style.height = height + 'px';
		}
	}
	
	// // small images
	let smallImageElements = document.querySelectorAll('.post-preview-container .horizontal-look > a');
	
	if(smallImageElements.length) {
		width = smallImageElements[0].offsetWidth;
		height = width / 2;
		for(let i = 0; i < smallImageElements.length; i++) {
			smallImageElements[i].style.height = height + 'px';
		}
	}
	}

function getCookie(cname) {
	var name = cname + '=';
	var decodedCookie = decodeURIComponent(document.cookie);
	var ca = decodedCookie.split(';');
	for (var i = 0; i < ca.length; i++) {
		var c = ca[i];
		while (c.charAt(0) == ' ') {
			c = c.substring(1);
		}
		if (c.indexOf(name) == 0) {
			return c.substring(name.length, c.length);
		}
	}
	return '';
	}

function setCookie(cname, cvalue, exdays) {
	var d = new Date();
	d.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1000);
	var expires = 'expires=' + d.toUTCString();
	document.cookie = cname + '=' + cvalue + ';' + expires + ';path=/';
	}

Datei nach dem Umstieg (JavaScript)

let sidebarScrollEnabled = true;


ready(() => {

	// priavy container on visit begin
	if (!getCookie('cookie-state') || getCookie('cookie-state') == undefined || getCookie('cookie-state') == '') {
		openCookieMenu();
	}
	
	
	// open cookie menu
	document.querySelectorAll('.open-cookie-menu').forEach(cookieMenu => {
		cookieMenu.addEventListener('click', openCookieMenu);
	});
	
	
	// set perfect image ratio
	setImageRatio();
	
	
	// position share buttons
	positionSocialIcons();
	
	
	// set perfect image ratio on resize
	let resizeTimeout;
	window.addEventListener('resize', () => {
		clearTimeout(resizeTimeout);
		resizeTimeout = setTimeout(() => {
			setImageRatio();
			positionSocialIcons();
		}, 200);
	});
	
	
	// toggle mobile submenus
	document.querySelectorAll('.main-menu .submenu-expand').forEach(expander => {
		expander.addEventListener('click', toggleMobileSubMenus);
	});
	
	
	// toggle mobile menu
	document.querySelector('.mobile-menu-button').addEventListener('click', toggleMobileMenu);
	
	
	// remove ad containers
	setTimeout(checkAdblock, 1500);
	
	
	// show shadow in header
	window.addEventListener('scroll', () => {
		toggleHeaderShadow();
	}, {passive: true});
	
	
	// sidebar scroll actions: TODO
	let windowScrollTimeout;
	window.addEventListener('scroll', () => {
		clearTimeout(windowScrollTimeout);
		sidebarScrollEnabled = false;
		windowScrollTimeout = setTimeout(() => {
			sidebarScrollEnabled = true;
		}, 1000);
	}, {passive: true});
	
	setInterval(() => {
		execSidebarMovementActions();
	}, 7*1000);
	
	
	// lightbox
	document.querySelectorAll('figure > a > picture > img, figure > a > img').forEach(lightboxLink => {
		lightboxLink.addEventListener('click', openLightbox);
	});
	
	
	// show social icons
	showSocialIcons(parseFloat(getComputedStyle(document.querySelector('html'), null).width.replace("px", "")) <= 768);
	
	
	// collect matomo data
	registerMatomoEventListeners();
	
	
	// minimize code blocks
	document.querySelectorAll('.wp-block-code, .enlighter-default').forEach(codeblock => {
		minimizeCodeblocks(codeblock);
	});
	
	
	// scroll to (with offset)
	document.querySelectorAll('a[href^="#"').forEach(anchorLink => {
		anchorLink.addEventListener('click', anchorClick);
	});
	
	
	// smooth scroll on page load
	setTimeout(() => {
		if(location.hash) {
			window.scrollTo(0, 0);
			let target = location.hash.split('#');
			customScrollTo(document.getElementById(target[1]));
		}
	}, 200);
	
	});


/* FUNCTION AREA */
function ready(fn) {
  if (document.readyState != 'loading'){
    fn();
  } else {
    document.addEventListener('DOMContentLoaded', fn);
  }
  }

function positionSocialIcons() {
	let iconWrapper = document.querySelector('.social-icons-fixed .social-icons');
	
	if(!iconWrapper) return false;
	
	if(parseFloat(getComputedStyle(document.querySelector('html'), null).width.replace("px", "")) < 768) {
		iconWrapper.style.left = 'inherit';
		iconWrapper.style.top = 'inherit';
		iconWrapper.style.bottom = '1rem';
		iconWrapper.style.right = '1rem';
	} else {
		let blogpost = document.getElementsByClassName('post')[0];
		iconWrapper.style.right = 'inherit';
		iconWrapper.style.bottom = 'inherit';
		iconWrapper.style.left = (blogpost.offsetLeft - 60) + 'px';
		iconWrapper.style.top = '100px';
	}
	}

function anchorClick(event) {
	event.preventDefault();
	let hrefSplit = event.target.href.split('#');
	let elementID = hrefSplit[1];
	
	if(elementID == undefined || elementID == '') return false;
	
	let element = document.getElementById(elementID);
	
	customScrollTo(element);
	}

function customScrollTo(element) {
	location.replace('#' + element.id);
	
	if (element == null) return false;
	
	var elementOffset = element.getBoundingClientRect().top + window.pageYOffset - 110
	
	window.scrollTo({
		top: elementOffset,
		behavior: 'smooth'
	});
	
	}

function expandCode(event) {
	event.preventDefault();
	
	if(event.target.classList.contains('open')) {	// minimize code
		event.target.parentNode.querySelector('.enlighter').style.height = '470px';
		event.target.parentNode.style.height = '534px';
		
		event.target.classList.remove('open');
		event.target.innerHTML = (lang === 'de' ? 'Aufklappen' : 'Expand');
	} else {	// maximize code
		event.target.parentNode.querySelector('.enlighter').style.height = 'auto';
		event.target.parentNode.style.height = 'auto';
		
		event.target.classList.add('open');
		event.target.innerHTML = (lang === 'de' ? 'Zuklappen' : 'Collapse');
	}
	}

function minimizeCodeblocks(codeblock) {
	if(codeblock.offsetHeight >= 450) {
		codeblock.querySelector('.enlighter').style.height = '470px';
		codeblock.querySelector('.enlighter').style.display = 'block';
		codeblock.style.height = '534px';
		
		let expandButton = document.createElement('span');
		expandButton.classList.add('expand-code');
		expandButton.classList.add('btn');
		expandButton.classList.add('btn-block');
		expandButton.classList.add('btn-sm');
		expandButton.classList.add('btn-primary');
		expandButton.classList.add('mt-2');
		expandButton.innerHTML = (lang === 'de' ? 'Aufklappen' : 'Expand');
		expandButton.onclick = expandCode;
		codeblock.appendChild(expandButton);
	}
	}



function registerMatomoEventListeners() {
	// collect menu data
	document.querySelectorAll('.menu-hauptmenue-container .sub-menu .menu-item a, .menu-hauptmenue-en-container .sub-menu .menu-item a').forEach(elem => {
		elem.addEventListener('click', () => {
			_paq.push(['trackEvent', 'Desktop Menu', 'Click', 'Open: "' + elem.innerHTML + '"']);
		});
	});
	
	
	// collect sidebar click
	document.querySelectorAll('.menu-sidebar-tutorials-de-container li a, .menu-sidebar-tutorials-en-container li a').forEach(elem => {
		elem.addEventListener('click', () => {
			_paq.push(['trackEvent', 'Sidebar Tutorials Menu', 'Click', 'Open: "' + elem.innerHTML + '"']);
		});
	});
	
	
	// collect sidebar click
	document.querySelectorAll('.sidebar-categories a, sidebar-categories a').forEach(elem => {
		elem.addEventListener('click', () => {
			_paq.push(['trackEvent', 'Sidebar Categories Menu', 'Click', 'Open: "' + elem.innerHTML + '"']);
		});
	});
	
	
	// collect InPost Menu click
	document.querySelectorAll('.interesting-container li a').forEach(elem => {
		elem.addEventListener('click', () => {
			_paq.push(['trackEvent', 'Interesting InPost Menu', 'Click', 'Open: "' + elem.innerHTML + '"']);
		});
	});
	
	
	// collect Table of contents click
	document.querySelectorAll('.table-of-contents li a').forEach(elem => {
		elem.addEventListener('click', () => {
			_paq.push(['trackEvent', 'Table of contents', 'Click', 'Jump to: "' + elem.innerHTML + '"']);
		});
	});
	
	// collect logo click
	document.querySelectorAll('.custom-logo-link').forEach(elem => {
		elem.addEventListener('click', () => {
			_paq.push(['trackEvent', 'Link', 'Click', 'Logo Click']);
		});
	});
	}

function showSocialIcons(mobile) {
	if (mobile) {
		document.querySelectorAll('.social-icons.vertical .share-icon').forEach(icon => {
			icon.classList.add('wd-show');
			icon.addEventListener('click', () => {
				document.querySelectorAll('.social-icons.vertical a').forEach(iconElement => {
				
					if(iconElement.classList.contains('wd-show')) {
						iconElement.classList.remove('wd-show');
					} else {
						iconElement.classList.add('wd-show');
					}
					
				});
			});
		});
	} else {
		setTimeout(function() {
			document.querySelectorAll('.social-icons.vertical a').forEach(icon => {
				icon.classList.add('wd-show');
			});
		}, 5000);
	}
	}

function openLightbox(event) {
	event.preventDefault();
	
	if(event.target.src != '') {
		let lightboxContent = '<div class="close">✖</div><img loading="lazy" src="' + event.target.src + '"><p>' + event.target.alt + '</p>';
		let lightboxContainer = document.querySelector('.lightbox .img-container');
		
		lightboxContainer.innerHTML = lightboxContent;
		document.querySelector('.lightbox').classList.add('wd-show');
		
		// _paq.push(['trackEvent', 'Lightbox', 'Click', 'Open Lightbox']);
		
		let closeElements = document.querySelectorAll('.lightbox .close, .lightbox .bg-overlay');
		closeElements.forEach(closeElement => {
			closeElement.removeEventListener('click', closeLightboxEvent);
			closeElement.addEventListener('click', closeLightboxEvent);
		})
	}
	}

function closeLightboxEvent() {
	document.querySelector('.lightbox').classList.remove('wd-show');
	}

function execSidebarMovementActions() {
	let jsToTopContainer = document.querySelector('.sidebar-outer-box .js-to-top-container');
	
	if(parseFloat(getComputedStyle(document.querySelector('html'), null).width.replace("px", "")) > 1200 && sidebarScrollEnabled) {
		let offset = window.pageYOffset;
		let singleAfterContent = document.querySelector('.single-after-content');
		let singleAfterContentViewport = singleAfterContent.getBoundingClientRect();
		let singleAfterContentOffset = singleAfterContentViewport.top + window.scrollY;
		let margin = 110;
		let sidebarAd = document.querySelector('.sidebar-box.cwebdeasy-g-container');
		
		if(sidebarAd) {
		
			let sidebarAdHeight = sidebarAd.offsetHeight;
			let sidebarAdOffsetBottom = sidebarAd.getBoundingClientRect().top + sidebarAdHeight;
			if(sidebarAd) margin += sidebarAdHeight;
			
			if(window.pageYOffset < margin) {
				jsToTopContainer.style.marginTop = '1rem';
			} else {
				jsToTopContainer.style.marginTop = (window.pageYOffset - margin) + 'px';
			}
			
		} else {
			jsToTopContainer.style.marginTop = (window.pageYOffset - margin) + 'px';
		}
		
	} else if(parseFloat(getComputedStyle(document.querySelector('html'), null).width.replace("px", "")) <= 1200) {
		jsToTopContainer.style.marginTop = '0px';
	}
	}

function toggleHeaderShadow() {
	let offset = window.pageYOffset;
	let header = document.querySelector('header#masthead');
	
	if(offset > header.offsetHeight) {
		header.classList.add('header-box-shadow');
	} else {
		header.classList.remove('header-box-shadow');
	}
	}

function checkAdblock() {
	let adblockEnabled = false;
	
	let adCheckElement = document.createElement('div');
	adCheckElement.classList.add('adBanner');
	document.querySelector('body').appendChild(adCheckElement);
	
	let adElement = document.getElementsByClassName('adBanner')[0];
  	let adElementStyle = getComputedStyle(adElement, null);
  	
  	if(adElementStyle.display === 'none') {   // Adblock enabled
  		document.querySelectorAll('.cwebdeasy-g-container').forEach(adElement => {
  			adElement.remove();
  		});
  		document.querySelectorAll('.webd-f-container').forEach(adElement => {
  			adElement.remove();
  		});
  	}
  	}

function openCookieMenu() {
	document.querySelector('.privacy-popup').classList.add('wd-show');
	initCookieClicker();
	}

function initCookieClicker() {
	let acceptCookiesButton = document.querySelector('.privacy-popup .privacy-container #accept-cookies');
	let necessaryCookiesButton = document.querySelector('.privacy-popup .privacy-container #necessary-cookies');
	let showCookiesButton = document.querySelector('.privacy-popup .privacy-container #show-cookies');
	
	acceptCookiesButton.removeEventListener('click', acceptCookiesButtonAction);
	acceptCookiesButton.addEventListener('click', acceptCookiesButtonAction);
	
	necessaryCookiesButton.removeEventListener('click', necessaryCookiesButtonAction);
	necessaryCookiesButton.addEventListener('click', necessaryCookiesButtonAction);
	
	showCookiesButton.removeEventListener('click', showCookiesButtonAction);
	showCookiesButton.addEventListener('click', showCookiesButtonAction);
	}

function acceptCookiesButtonAction() {
	setCookie('cookie-state', 'all', 7);
	
	_paq.push(['forgetUserOptOut']);
	
	document.querySelector('.privacy-popup').classList.remove('wd-show');
	}

function necessaryCookiesButtonAction() {
	setCookie('cookie-state', 'necessary', 7);
	
	_paq.push(['optUserOut'])
	
	document.querySelector('.privacy-popup').classList.remove('wd-show');
	}

function showCookiesButtonAction() {
	let cookieInfos = document.querySelector('.privacy-popup .more-cookie-infos');
	if(cookieInfos.classList.contains('wd-show')) {
		cookieInfos.classList.remove('wd-show');
	} else {
		cookieInfos.classList.add('wd-show');
	}
	}

function setImageRatio() {
	// normal preview
	let imageElements = document.querySelectorAll('.post-preview-container .header-container');
	
	if(imageElements.length) {
		let width = imageElements[0].offsetWidth;
		let height = width / 2;
		for(let i = 0; i < imageElements.length; i++) {
			imageElements[i].style.height = height + 'px';
		}
	}
	
	// // small images
	let smallImageElements = document.querySelectorAll('.post-preview-container .horizontal-look > a');
	
	if(smallImageElements.length) {
		width = smallImageElements[0].offsetWidth;
		height = width / 2;
		for(let i = 0; i < smallImageElements.length; i++) {
			smallImageElements[i].style.height = height + 'px';
		}
	}
	}

function getCookie(cname) {
	var name = cname + '=';
	var decodedCookie = decodeURIComponent(document.cookie);
	var ca = decodedCookie.split(';');
	for (var i = 0; i < ca.length; i++) {
		var c = ca[i];
		while (c.charAt(0) == ' ') {
			c = c.substring(1);
		}
		if (c.indexOf(name) == 0) {
			return c.substring(name.length, c.length);
		}
	}
	return '';
	}

function setCookie(cname, cvalue, exdays) {
	var d = new Date();
	d.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1000);
	var expires = 'expires=' + d.toUTCString();
	document.cookie = cname + '=' + cvalue + ';' + expires + ';path=/';
	}

function toggleMobileSubMenus(event) {
	event.preventDefault();
	
	if(parseFloat(getComputedStyle(document.querySelector('html'), null).width.replace("px", "")) < 1200) {
	
		let childs = event.target.parentNode.parentNode.children;
		
		for(let i = 0; i < childs.length; i++) {
		
			if(childs[i].classList.contains('sub-menu')) {
			
				if(childs[i].classList.contains('wd-show')) {
					childs[i].classList.remove('wd-show');
				} else {
					childs[i].classList.add('wd-show');
				}
				
			}
			
		}
		
	}
	}

function toggleMobileMenu(event) {
	event.preventDefault();
	let button = document.querySelector('.mobile-menu-button');
	let mobileMenuOverlay = document.querySelector('.mobile-menu-bg-overlay');
	
	
	if(button.classList.contains('open')) {	// close menu
		button.classList.remove('open');
		
		document.querySelectorAll('.menu-hauptmenue-container, .menu-hauptmenue-en-container').forEach(menu => {
			menu.classList.remove('wd-show');
		});
		
		mobileMenuOverlay.classList.remove('wd-show');
		mobileMenuOverlay.removeEventListener('click', mobileMenuOverlayClick);
		
	} else {	// open menu
		button.classList.add('open');
		
		document.querySelectorAll('.menu-hauptmenue-container, .menu-hauptmenue-en-container').forEach(menu => {
			menu.classList.add('wd-show');
		});
		
		mobileMenuOverlay.classList.add('wd-show');
		mobileMenuOverlay.addEventListener('click', mobileMenuOverlayClick);
		
		_paq.push(['trackEvent', 'Menu', 'Click', 'Open mobile menu']);
		
	}
	}

function mobileMenuOverlayClick() {
	var event = document.createEvent('HTMLEvents');
	event.initEvent('click', true, false);
	document.querySelector('.mobile-menu-button').dispatchEvent(event);
	}

Ich glaube es wird auch deutlich, was ich mit Aufräumen von Code meine.

Natürlich sollte immer das Ziel sein, Code möglichst wartbar zu entwickeln. Solche Dateien wachsen aber historisch und ich bin natürlich auch selber schuld, dass so ein Chaos entsteht…

Lohnt sich der Aufwand überhaupt?

In meinen Augen: Ja! Neben dem Clean-Up meines Codes habe ich unnötige Funktionen direkt entfernt. Das freut auch die Besucher Deiner Seite.

Ich dachte, dass es ohne jQuery nicht geht. Aber wenn Du wirklich alles aus Deiner Seite rausholen willst, ist das ein guter Schritt.

Ähnliche Beiträge
NEW 🚀
Schreib einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.