JQuery, prüfen ob Maus über Box (immernoch) befindet

Grille

Erfahrenes Mitglied
Guten Tag,

ich versuche ein horizontales Menü zu programmieren, so wie dieses unterhalb des Banners auf dieser Seite steht:

Graphic Design Services | 99designs

ich habe jetzt die Abfrage des Containers und das ganze bewegt sich auch schon, leider habe ich probleme mit der Maus.

Bei "onmousemove" muss ich immerzu die Maus bewegen damit sich das Menü bewegt.

Ich möchte aber dauerhaft: "wenn die Maus über dem Menü-Container steht oder bewegt, soll sich das Menü bewegen".

HTML:
<div id="lmenue" class="position-1">
    <ul class="nav menumenueleistungen mod-list" style="left: 0px; position: relative;">
        <li class="item-132"><a href="1"> Punkt 1 </a></li>
        <li class="item-133"><a href="2"> Punkt 2 </a></li>
        <li class="item-134"><a href="3"> Punkt 3 </a></li>
        <li class="item-135"><a href="4"> Punkt 4 </a></li>
        <li class="item-136"><a href="5"> Punkt 5 </a></li>
        <li class="item-137"><a href="6"> Punkt 6 </a></li>
        <li class="item-138"><a href="7"> Punkt 7 </a></li>
        <li class="item-139"><a href="8"> Punkt 8 </a></li>
    </ul>
</div>

Javascript:
jQuery(function($){
    var view = $(window).width(); // Breite des sichtbaren Fensters
    var drossel = 10; // drosselt die Animation
    var bewegung = 0; // Variable zum berechnen der Position, damit sich das Menü nur so weit bewegt, wie es übersteht.
    $("ul.menumenueleistungen").css({left: bewegung, position:'relative'}); // erste Positionierung

    // berechnen der Menülänge
    var menueweite = 0; // Berechnung der Breite des gesamten Menüs durch aneinanderrechnen der einzelnen Listen-Breiten
    $("ul.menumenueleistungen li").each(function() {
        menueweite += $(this).width();
        menueweite += 20;
    });

    var ueberstand = menueweite - $(window).width(); // feststellen, wie weit das Menü sich außerhalb der Webseite befindet
    var bereich = view/4; // festlegen, wie breit der Bereich ist, wo die Maus die Menüanimation rechts oder links auslösen soll

    document.getElementById('lmenue').onmousemove = function(evt) { // wenn die Maus sich auf dem Container bewegt, dann ...
        let  elem = evt.target; // ... stelle die Position fest
        var ueberstand = menueweite - $(window).width(); // ... feststellen, wie weit das Menü sich außerhalb der Webseite befindet

        var links = Math.floor((bereich-evt.pageX)/drossel); // ... Wert, wie schnell sich das Menü bewegen soll, wenn die Maus im linken Bereich ist
        if (links < 10){ links = 0;} // unterschreitet "links" einen Wert, dann soll die Variable "0" sein

        var rechts = Math.floor((evt.pageX-(view-bereich))/drossel); // ... Wert, wie schnell sich das Menü bewegen soll, wenn die Maus im rechten Bereich ist
        if (rechts < 10){ rechts = 0;} // unterschreitet "rechts" einen Wert, dann soll die Variable "0" sein

        // Bewegungsberechnung "links"
        if (bewegung < 0  && links != 0){
            if (0 > bewegung + links){
                bewegung = bewegung + links;
            } else {
                bewegung = 0;
            }
        }

        // Bewegungsberechnung "rechts"
        if ((ueberstand * (-1)) < bewegung && rechts != 0){
            if ((ueberstand * (-1)) < bewegung - rechts){
                bewegung = bewegung - rechts;
            } else {
                bewegung = ueberstand * (-1);
            }
        }

        // Ausgabe über Console
        console.log('links ' + links + "; rechts: " + rechts + "; bewegung: " + bewegung + "; ueberstand: " + ueberstand);

        // Modifikation - Bewegung des Menüs
        $("ul.menumenueleistungen").css({left: bewegung, position:'relative'});
    }
});

Ich neige dazu, Dinge kompliziert zu konstruieren.
Vielleicht habt Ihr auch eine einfachere Lösung?

Vielen Dank und einen schönen Tag euch.

Grille
 

basti1012

Erfahrenes Mitglied
Ich kann das jetzt nicht alles testen so wie du es da hast, aber JQuery besitzt hover().
Ohne da jetzt weiter frauf einzugehen, schmeiße ich mal das in Raum
Code:
$('#lmenue').hover(function(){
     console.log('Ich bin auf den menü')
})
Dann abfragen, ob die Maus mehr rechts oder Links ist und dann darauf reagieren.
Ungetestet, aber das wäre mein Versuchsansatz
 

Sempervivum

Erfahrenes Mitglied
Ich würde es schon mit mousemove machen und zwar bei jeder Mausbewegung prüfen, ob die Maus im rechten oder linken Bereich ist und abhängig von der Position die Geschwindigkeit bzw. das Wegintervall berechnen und in einer globalen Variablen speichern. Damit sich das Menü kontinuierlich bewegt, requestAnimationFrame benutzen und in der Callback-Funktion die Position des Menüs abhängig von Geschw. bzw. Intervall in der Variablen bewegen.
 

basti1012

Erfahrenes Mitglied
Stimmt auch wieder, ohne Maus Event kommt man auch nicht weit.
Dann ist ja auch die Frage was genau passieren soll.
Wenn man z. B. die Maus etwas weiter als die Mitte positioniert, soll das Menü dann ganz nach recht Sliden , oder nur so weit wie Prozentual die Maus von den innen Container ist.
Soll das Sliden erst langsam und dann schneller werden und so weiter.?

Theoretisch reichen paar Zeilen dafür,
https://codepen.io/basti1012/pen/gOLYgVQ?editors=1011
Transition Zeit ändern, ändert den Speed. Es sollte auch Responsiv sein hoffe ich.

Noch nicht Perfekt.
Vielleicht schmeißt ihr auch noch paar Lösungen in Raum, mich würden andere Möglichkeiten da auch interessieren,
 

Sempervivum

Erfahrenes Mitglied
Meine Version, wie oben beschrieben:
Code:
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>Sliding Menu</title>
    <style>
        #lmenue {
            width: 100%;
            position: relative;
            height: 5em;
            overflow: hidden;
        }

        #lmenue ul.nav {
            list-style-type: none;
            height: 100%;
            position: absolute;
            left: 0;
            top: 0;
            display: flex;
            padding: 0;
            margin: 0;
        }

        #lmenue ul.nav li {
            padding: 2em 5em;
            border: 2px solid lightblue
        }

        #lmenue ul.nav li a {
            white-space: nowrap;
        }
    </style>

</head>

<body>
    <div id="lmenue" class="position-1">
        <ul class="nav menumenueleistungen mod-list">
            <li class="item-132"><a href="1"> Punkt 1 </a></li>
            <li class="item-133"><a href="2"> Punkt 2 </a></li>
            <li class="item-134"><a href="3"> Punkt 3 </a></li>
            <li class="item-135"><a href="4"> Punkt 4 </a></li>
            <li class="item-136"><a href="5"> Punkt 5 </a></li>
            <li class="item-137"><a href="6"> Punkt 6 </a></li>
            <li class="item-138"><a href="7"> Punkt 7 </a></li>
            <li class="item-139"><a href="8"> Punkt 8 </a></li>
        </ul>
    </div>
    <script>
        const factor = 0.02,
            cont = document.querySelector('#lmenue'),
            slide = document.querySelector('#lmenue ul.nav'),
            wSlide = slide.getBoundingClientRect().width;
        let speed = 0, pos = 0,
            left, right, topCont, width, height;
        // Parameter des Containers ermitteln
        // Diese sind abhängig von der Breite des Viewports
        function onRes() {
            const boundingRect = cont.getBoundingClientRect();
            left = boundingRect.left;
            right = boundingRect.right;
            topCont = boundingRect.top;
            width = boundingRect.width;
            height = boundingRect.height;
        }
        window.addEventListener('resize', onRes);
        onRes();
        cont.addEventListener('mousemove', event => {
            // Mausposition ermitteln
            const mouseX = event.clientX,
                mouseY = event.clientY;
            console.log(left, topCont, mouseX, mouseY);
            // Geschwindigkeit abhaengig von der Mausposition festlegen
            if (mouseX - left < width / 3) {
                speed = (width / 3 - mouseX) * factor;
            } else if (right - mouseX < width / 3) {
                speed = -(mouseX - width + width / 3) * factor;
            } else {
                speed = 0;
            }
            console.log(left, topCont, mouseX, mouseY, speed)
        });
        // Position des Menues animieren
        function moveIt() {
            // console.log('move', speed);
            // Nur wenn die Geschwindigkeit einen Schwellenwert überschreitet
            if (Math.abs(speed) > factor &&
                // und die Position noch keine der Grenzen erreicht hat
                ((pos < 0 && speed > 0) || (pos > -(wSlide - width) && speed < 0))) {
                // Position entspr. Geschwindigkeit aendern
                pos += speed;
                slide.style.left = pos + 'px';
            }
            // Neuen Aufruf der Funktion anfordern
            requestAnimationFrame(moveIt);
        }
        // Animation starten
        moveIt();
    </script>
</body>

</html>
Etwas kompliziert geworden aber die Geschwindigkeit ändert sich schön geschmeidig, je weiter man mit der Maus nach links oder rechts geht.
 

Grille

Erfahrenes Mitglied
Vielen Dank euch beide - sorry dass ich erst jetzt Antworte.

Beim Code von Basti gefällt mir, dass er so schön kurz ist. Leider reicht hier mein Durchblick nicht, um das Menü weiter zu optimieren.

Ich werde den Code von Sempervivum nutzen, weil er sehr flüssig funktioniert.

Vielen Dank.
 

basti1012

Erfahrenes Mitglied
Man kann auch mit wenig Code viel erreichen.
Du siehst zwar das mein Code eigentlich das macht, was er machen soll.
Je weiter man zum Rand kommt, wird er schneller werden.
Beim Maus loslassen läuft er weiter bis zum Ende und sogar responsive.

Aber es ist so nicht Perfekt.
Man müsste da auch noch paar Zeilen reinbauen bis es Perfekt.

Sempervivum's Lösung mit requestAnimation finde ich ganz gut.
Ich habe gestern auch mit Animate() getestet, wahr aber nicht zufrieden stellend.
Das beim mittleren drittel beim mousover nichts passiert ist eigentlich auch nee gute Idee, dann sieht man die Reaktionen besser und es sieht flüssiger aus.

Bei mir reagiert er schon, wenn du ein Pixel von der Mitte weg bist und deswegen sieht das wohl auch alles so träge aus.
 

Neue Beiträge