I have a simple sidebar designed in HTML and I have developed a script where the sidebar closes and opens when the mouse enters and mouse leaves respectively.
You can check out the DEMO here.
I have used Vue.js instance for the whole sidebar, everything works perfectly except when the mouse hovers any of the items in the side bar then when the mouse leaves, the closing of the side bar is very slow.
You should use mouseenter instead of mouseover ..
<div id="custom-erp-id-side-nav" class="custom-erp-side-nav" #mouseenter="openSideBar" #mouseleave="closeSideBar">
Codepen
You can change the animate time, for example set 50
closeSideBar: function() {
$("#custom-erp-id-side-nav")
.off()
.animate({ left: "-230px" }, 50);
}
What is happening is that you're queueing up a lot of events. In some situations, you can get an opening-and-closing loop that keeps going until you move your mouse. This happens even if you use mouseenter instead of mouseover.
You can have your open and close routines each set a gatekeeper variable to ensure that they don't try multiple opens (or closes). In the complete parameter of animate, you unset the gatekeeper variable.
openSideBar: function() {
if (!this.opening) {
this.opening = true;
$("#custom-erp-id-side-nav")
.off()
.animate({
left: "0px"
}, null, null, () => {
this.opening = false;
});
}
},
closeSideBar: function() {
if (!this.closing) {
this.closing = true;
$("#custom-erp-id-side-nav")
.off()
.animate({
left: "-230px"
}, null, null, () => {
this.closing = false;
});
}
}
// vue instance for the sidebar menu
var erp_custom_side_bar = new Vue({
el: "#custom-erp-id-side-nav",
data: {},
methods: {
//function to close/open the child elements
//when the parent menu is clicked.
toggleOpenChild: function(event) {
var currentParent = $(event.currentTarget)
.find(".custom-erp-menu-parent")
.text();
var childListID = currentParent.toLowerCase().replace(/ /g, "-");
$(".custom-erp-menu-list > ul")
.not($("#" + childListID + "-child"))
.slideUp()
.removeClass("custom-erp-menu-child-open");
if ($("#" + childListID + "-child").is(":hidden")) {
$("#" + childListID + "-child")
.slideDown(300)
.toggleClass("custom-erp-menu-child-open");
} else {
$("#" + childListID + "-child")
.slideUp(300)
.toggleClass("custom-erp-menu-child-open");
}
},
openSideBar: function() {
if (!this.opening) {
this.opening = true;
$("#custom-erp-id-side-nav")
.off()
.animate({
left: "0px"
}, null, null, () => {
this.opening = false;
});
}
},
closeSideBar: function() {
if (!this.closing) {
this.closing = true;
$("#custom-erp-id-side-nav")
.off()
.animate({
left: "-230px"
}, null, null, () => {
this.closing = false;
});
}
}
}
});
.custom-erp-side-nav {
height: 100%;
width: 240px;
position: fixed;
z-index: 1;
top: 56px;
left: 0;
background-color: #2b333e;
overflow-x: hidden;
padding-top: 20px;
left: -230px;
}
.custom-erp-side-nav-open {
left: 0;
}
.custom-erp-menu-list a {
padding: 10px 5px 10px 40px;
text-decoration: none;
letter-spacing: 0.3px;
font-size: 16px;
color: #aeb7c2;
display: block;
}
.custom-erp-menu-list>a {
padding-left: 20px;
}
.custom-erp-menu-list a:hover {
color: #f1f1f1 !important;
background-color: rgb(56, 65, 74);
}
.custom-erp-menu-list a:hover .custom-erp-module-list-icon {
filter: brightness(0) invert(1);
}
.custom-erp-module-list-icon {
margin-right: 10px;
}
.custom-erp-menu-child-dropdown {
display: none;
background-color: #252c35;
border-left: 3px solid #3cabfe;
}
.custom-erp-menu-child-dropdown>a:hover {
background-color: rgb(56, 65, 74);
}
#custom-erp-menu-lists {
padding-left: 0px !important;
}
.custom-erp-menu-child-open {
display: block;
}
<script src="https://unpkg.com/vue#latest/dist/vue.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="custom-erp-id-side-nav" class="custom-erp-side-nav" #mouseover="openSideBar" #mouseleave="closeSideBar">
<nav id="custom-erp-menu-nav">
<ul id="custom-erp-menu-lists">
<li class="custom-erp-menu-list" v-on:click="toggleOpenChild">
<a href="#">
<span>
<img src="assets/images/dollar-bills.svg" class="custom-erp-module-list-icon custom-erp-user-icons" width="18" height="18" alt="">
</span>
<span class="custom-erp-menu-parent">Purchase Order</span>
</a>
<ul class="nav custom-erp-menu-child-dropdown" id="purchase-order-child">
<li>Profile</li>
<li>Login</li>
<li>Lockscreen</li>
</ul>
</li>
<li class="custom-erp-menu-list" v-on:click="toggleOpenChild">
<a href="#">
<span>
<img src="assets/images/dollar-bills.svg" class="custom-erp-module-list-icon custom-erp-user-icons" width="18" height="18" alt="">
</span>
<span class="custom-erp-menu-parent">Expense</span>
</a>
<ul class="nav custom-erp-menu-child-dropdown" id="expense-child">
<li>Profile</li>
<li>Login</li>
<li>Lockscreen</li>
</ul>
</li>
</ul>
</nav>
</div>
Related
I am hacking together an experimental pagination interface called wigi(board) but have run into an issue.
The interface works by any l1 (subject) class or l2 (subheading) class running vertical down the left. Pages (l3 class nodes) are represented as points attached to the side of an l1 or l2.
Mousing over any node will move the selector to that node and call a db query to display a specific page's contents. This works fine. It moves like it should.
Right now I have buttons that will also move between the next and previous li in the navigation list. These are filler for future swiping and other interaction to demonstrate the issue.
Right now these buttons work to a point, until the jquery .next() hits a <br> node, which I am using in order to break the l3 lines and continue the menu vertical to the next l1 or l2. When the .next hits the last node before one of these, it stops dead and wont jump down to the next row. Why? What is the best strategy to fix it?
JS fiddle: http://jsfiddle.net/93g786jp/
The issue with next is in here. It is running over an li list (best to look at JSfiddle)
function nextAndBack(e) {
var cur = $('.dots .selected'),
next = cur.next('li'),
prev = cur.prev('li');
if (e.target.id == 'nextButton') {
if (next.length == 1) {
newSelected(next);
console.log("Next Node:")
console.log(next);
$(next).trigger("mouseover");
}
} else if (e.target.id == 'prevButton') {
if (prev.length == 1) {
newSelected(prev);
console.log("Previous Node:")
console.log(prev);
$(prev).trigger("mouseover");
}
}
}
Note this is based on the gooey interface by Lucas Bebber # https://codepen.io/lbebber/pen/lFdHu which was the closet match I could find for an interface like what I wanted. For the posted example, I stripped out any effects and other extras so some stubs exist.
As the <br /> gets in the way of selecting siblings you can instead use nextAll() or prevAll() and then get the first() of the selected items:
next = cur.nextAll('li').first(),
prev = cur.prevAll('li').first();
function wigiBoardMove() {
var cur = $(this);
var desty = cur.position().top;
var destx = cur.position().left;
var t = 0.6;
gsap.to($(".select"), t, {
y: desty,
ease: Back.easeOut
});
gsap.to($(".select"), t, {
x: destx,
ease: Back.easeOut
});
newSelected(cur);
}
function newSelected(newTarget) {
$('.selected').removeClass('selected');
newTarget.addClass('selected');
}
function nextAndBack(e) {
var cur = $('.dots .selected'),
next = cur.nextAll('li').first(),
prev = cur.prevAll('li').first();
if (e.target.id == 'nextButton') {
if (next.length == 1) {
newSelected(next);
$(next).trigger("mouseover");
}
} else if (e.target.id == 'prevButton') {
if (prev.length == 1) {
newSelected(prev);
$(prev).trigger("mouseover");
}
}
}
/* Modified from gooey pagnation code published by Lucas Bebber # https://codepen.io/lbebber/pen/lFdHu */
$(function() {
$(".dot").on("mouseenter", wigiBoardMove);
var lastPos = $(".select").position().top;
function updateScale() {
var pos = $(".select").position().top;
var speed = Math.abs(pos - lastPos);
var d = 44;
var offset = -20;
var hd = d / 2;
var scale = (offset + pos) % d;
if (scale > hd) {
scale = hd - (scale - hd);
}
scale = 1 - ((scale / hd) * 0.35);
gsap.to($(".select"), 0.1, {
scaleY: 1 + (speed * 0.06),
scaleX: scale
})
lastPos = pos;
requestAnimationFrame(updateScale);
}
requestAnimationFrame(updateScale);
$(".dot:eq(0)").trigger("mouseover");
// Back and Forward Node Logic
$('#nextButton, #prevButton').on('click', nextAndBack);
})
#container {}
.dots {
list-style-type: none;
padding: 0;
margin: 0;
padding-top: 20px;
padding-bottom: 20px;
padding-left: 20px;
margin-left: -10px;
padding-right: 10px;
position: absolute;
top: 0px;
width: 150px;
right: 0px;
}
.dot {
display: inline-block;
vertical-align: middle;
margin-left: 5px;
margin-right: 5px;
cursor: pointer;
color: white;
position: relative;
z-index: 2;
}
.l1 {
border-radius: 100%;
width: 10px;
height: 10px;
background: blue;
border: none;
}
.l3 {
border-radius: 100%;
width: 7px;
height: 7px;
border: none;
background: blue;
}
.select {
display: block;
border-radius: 100%;
width: 15px;
height: 15px;
background: #daa520;
position: absolute;
z-index: 3;
top: -4px;
left: 1px;
pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/gsap.min.js"></script>
<div id="container">
<ul class="dots">
<li class="select"></li>
<li class="dot l1"></li>
<li class="dot l3"></li>
<li class="dot l3"></li>
<li class="dot l3"></li><br>
<li class="dot l1"></li>
<li class="dot l3"></li>
<li class="dot l3"></li><br>
<li class="dot l1"></li>
<li class="dot l3"></li><br>
</ul>
<img id="nextButton" height="10" width="10" alt="Next Node" /><br>
<img id="prevButton" height="10" width="10" alt="Previous Node" />
</div>
I have 5 images which I wanted to display in a slideshow play. I have used the following code from internet and modified it slightly. The slideshow has two buttons, forward button on the right and backward button on the left. The forward button is functioning completely fine. When clicked on it, it correctly displays in the sequence:
Image_1 -> Image_2 -> Image_3 -> Image_4 -> Image_5 -> Image_1 -> Image_2 -> so on...
But the problem is in the backward button, it displays correctly as :
Image_5 -> Image_4 -> Image_3 -> Image_2 -> Image_1.
But after this, clicking again on backward button, I want it to show as Image_1 -> Image_5 without racing through Image_2 to Image_4. I am not able to do so. The function sliderFaLeft.on('click', function(){} in the file javascript.js is being created to do the same but unsuccessful.
/*File : javascript.js*/
$(function()
{
"use strict";
var main_image_class = $('.main_image_class'),
slider = main_image_class.find('.slider'),
sliderUl = slider.find('.slider-parent'),
sliderUlLi = sliderUl.find('.images-list'),
sliderOl = slider.find('.bottom-circles'),
sliderOlLi = sliderOl.find('.bottom-circles-list'),
sliderFaRight = slider.find('> .fa:first-of-type'),
sliderFaLeft = slider.find('> .fa:last-of-type'),
sliderTime = 1000,
sliderWait = 3000,
sliderSetInt,
resumeAndPause;
function resetWH()
{
slider.width(slider.parent().width()).height(slider.parent().width() * 0.5);
sliderUl.width(slider.width() * sliderUlLi.length).height(slider.height());
sliderUlLi.width(slider.width()).height(slider.height());
}
resetWH();
function runSlider()
{
if (sliderOlLi.hasClass('slider-active'))
{
sliderUl.animate(
{
marginLeft: -slider.width() * ($('.slider-active').data('slider') - 1)
},
sliderTime);
}
sliderFaLeft.fadeIn();
sliderFaRight.fadeIn();
}
function runRight()
{
slider.each(function()
{
$('.slider-active').next().addClass('slider-active').siblings().removeClass('slider-active');
runSlider();
});
}
function runLeft()
{
slider.each(function()
{
$('.slider-active').prev().addClass('slider-active').siblings().removeClass('slider-active');
runSlider();
});
}
sliderSetInt = function autoRunSlider()
{
if ($('.slider-active').next().is(':last-of-type'))
{
sliderUl.animate(
{
marginLeft: -sliderUlLi.width() * $('.slider-active').data('slider')
},
sliderTime,
function()
{
sliderUl.css('margin-left', 0);
sliderOlLi.first().addClass('slider-active').siblings().removeClass('slider-active');
});
}
else
{
runRight();
}
};
resumeAndPause = setInterval(sliderSetInt, sliderWait);
$(window).on('resize', function()
{
resetWH();
});
slider.each(function()
{
sliderOlLi.click(function()
{
$(this).addClass('slider-active').siblings().removeClass('slider-active');
runSlider();
});
});
sliderFaRight.on('click', function()
{
if ($('.slider-active').next().is(':last-of-type'))
{
sliderUl.animate(
{
marginLeft: -sliderUlLi.width() * $('.slider-active').data('slider')
},
sliderTime,
function()
{
sliderUl.css('margin-left', 0);
sliderOlLi.first().addClass('slider-active').siblings().removeClass('slider-active');
});
}
else
{
runRight();
}
});
sliderFaLeft.on('click', function()
{
if ($('.slider-active').is(':first-of-type'))
{
/*Missing Code to move the animation from first image to last image through movement in the right direction*/
}
else
{
runLeft();
}
});
slider.find('.fa').hover(function()
{
clearInterval(resumeAndPause);
},
function()
{
resumeAndPause = setInterval(sliderSetInt, sliderWait);
});
});
/*File : styles.css*/
.main_image_class .slider ul, .main_image_class .slider ol {
list-style: none;
}
.main_image_class {
width: 75%;
margin-left: auto;
margin-right: auto;
overflow: hidden;
color: #fff;
}
.slider {
position: relative;
}
.slider .slider-parent {
padding: 0;
display: flex;
}
.slider .slider-parent .images-list {
background-size: cover;
}
.slider .slider-parent .images-list:first-of-type, .slider .slider-parent .images-list:last-of-type {
background-image: url(facilities/classroom/image-1.jpeg);
}
.slider .slider-parent .images-list:nth-of-type(2) {
background-image: url(facilities/classroom/image-2.jpeg);
}
.slider .slider-parent .images-list:nth-of-type(3) {
background-image: url(facilities/classroom/image-3.jpeg);
}
.slider .slider-parent .images-list:nth-of-type(4) {
background-image: url(facilities/classroom/image-4.jpeg);
}
.slider .slider-parent .images-list:nth-of-type(5) {
background-image: url(facilities/classroom/image-5.jpg);
}
.slider .bottom-circles {
position: absolute;
transform: translate(-50%, -50%);
left: 50%;
bottom: 10px
}
.slider .bottom-circles .bottom-circles-list {
display: inline-block;
}
.slider > .fa {
position: absolute;
top: 45%;
}
.slider > .fa:first-of-type { right: 5px;}
.slider > .fa:last-of-type { left: 5px;}
.slider .fa {
text-shadow: 5px 5px 5px #555;
cursor: pointer;
color: yellow;
}
<!--File : index.html-->
<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="stylesheet" type="text/css" href="styles.css">
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css">
</head>
<body>
<div class="main_image_class">
<div class="slider">
<ul class="slider-parent">
<li class="images-list" data-slider="1"></li>
<li class="images-list" data-slider="2"></li>
<li class="images-list" data-slider="3"></li>
<li class="images-list" data-slider="4"></li>
<li class="images-list" data-slider="5"></li>
<li class="images-list" data-slider="6"></li>
</ul>
<ol class="bottom-circles">
<li class="bottom-circles-list slider-active" data-slider="1"><i class="fa fa-circle-thin"></i></li>
<li class="bottom-circles-list" data-slider="2"><i class="fa fa-circle-thin"></i></li>
<li class="bottom-circles-list" data-slider="3"><i class="fa fa-circle-thin"></i></li>
<li class="bottom-circles-list" data-slider="4"><i class="fa fa-circle-thin"></i></li>
<li class="bottom-circles-list" data-slider="5"><i class="fa fa-circle-thin"></i></li>
<li class="bottom-circles-list" data-slider="6"></li>
</ol>
<i class="fa fa-chevron-right fa-5x"></i>
<i class="fa fa-chevron-left fa-5x"></i>
</div>
</div>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript" src="javascript.js"></script>
</body>
</html>
One of the best way to achieve the goal is to get the length of the entire array of images, and, then use minus one. You can use for method:for(i = images.length; i > 0; i--) { images[i] = image }
This method will fetch that index of images
I have this code:
<template>
<div class="chart"
v-bind:style="chartStyleObject"
v-on:mousedown.left="initHandleMousedown($event)"
v-on:mouseup.left="initHandleMouseup()"
v-on:mouseout="initHandleMouseup()">
<div class="chartContent">
</div>
<!-- <div class="chartContent"> end -->
</div>
<!-- <div class="chart"> end -->
</template>
<script>
import axios from 'axios';
export default{
created () {
},
data () {
return {
ticket: null,
chartStyleObject: {
width: '500px',
widthWrapper: '1600px',
heightWrapper: '500px',
height: '247px',
marginTop: '15px',
marginRight: '0px',
marginBottom: '0px',
marginLeft: '15px',
},
XCoord: null,
YCoord: null,
}
},
methods: {
initHandleMousedown(event) {
this.startMousedownXCoord = event.clientX;
this.startMousedownYCoord = event.clientY;
this.XCoord = event.clientX;
this.YCoord = event.clientY;
console.log('XCoord', this.XCoord);
console.log('YCoord', this.YCoord);
window.addEventListener('mousemove', this.initHandleMouseMove);
},
initHandleMouseMove(event) {
this.XCoord = event.clientX;
this.YCoord = event.clientY;
console.log('XCoord', this.XCoord);
console.log('YCoord', this.YCoord);
},
initHandleMouseup() {
window.removeEventListener('mousemove', this.initHandleMouseMove);
},
},
}
</script>
<style scoped>
.chart{
position: relative;
border-radius: 10px;
padding: 27px 10px 10px 10px;
background-color: #45788b;
box-sizing: border-box;
cursor: move;
}
.chart .chartContent{
position: relative;
top: 0;
left: 0;
height: 100%;
width: 100%;
margin: 0 0 0 0;
background-color: #2f2c8b;
}
</style>
HTML design consists of 2 blocks:
(parent and child)
The event is tied to the parent tag `<div class =" chart ">`
Also, the parent block has padding on all 4 sides:
If you click on the parent block and drive with the mouse (holding the button pressed) without affecting the padding space, the mousemove event will fire without problems.
But as soon as the mouse cursor touches the padding territory, the event ceases to function.
If you click on the padding, the event also works correctly - but it stops working if I move the mouse cursor over the block space outside the paddings (internal space)
Question:
Why is this happening - and is this behavior normal for js + nuxt.js?
I can't exactly follow your descriptions of the various regions of the page but I can have a go at explaining what I think you're seeing.
The key to this is that you have a mouseout listener that removes your mousemove listener. The mouseout event propagates, which means it will fire even if the mouseout occurred on a child element. Contrast with mouseleave which will only fire if the event occurs on the element itself.
The example below illustrates how a mouseout listener will fire even if the mouse cursor doesn't leave the root element. Just moving the cursor outside a child is sufficient.
document.getElementById('outer').addEventListener('mouseout', () => {
document.getElementById('out').innerHTML += 'mouseout\n'
})
div {
border: 1px solid;
display: inline-block;
padding: 20px;
}
<div id="outer">
<div></div>
</div>
<pre id="out"></pre>
I suspect that when you observe the event ceasing to function what is actually happening is that a mouseout event is occurring and that is removing the mousemove listener.
skirtle answer is correct. I am only providing this answer to illustrate how to do it using your own code. The only line I changed was this v-on:mouseleave="initHandleMouseup(). Notice I changed it to mouseout to mouseleave.
To summarize:
mouseleave is fired once per element regardless of its children
hover.
mouseout is fired every time the element abandoned (whether
moving the mouse away or hovering over its children).
new Vue({
el: "#app",
template: `
<div class="chart"
v-bind:style="chartStyleObject"
v-on:mousedown.left="initHandleMousedown($event)"
v-on:mouseup.left="initHandleMouseup()"
v-on:mouseleave="initHandleMouseup()">
<div class="chartContent">
</div>
<!-- <div class="chartContent"> end -->
</div>
<!-- <div class="chart"> end -->
`,
created: function() {},
data() {
return {
ticket: null,
chartStyleObject: {
width: '500px',
widthWrapper: '1600px',
heightWrapper: '500px',
height: '247px',
marginTop: '15px',
marginRight: '0px',
marginBottom: '0px',
marginLeft: '15px',
},
XCoord: null,
YCoord: null,
}
},
methods: {
initHandleMousedown: function(event) {
this.startMousedownXCoord = event.clientX;
this.startMousedownYCoord = event.clientY;
this.XCoord = event.clientX;
this.YCoord = event.clientY;
console.log('XCoord', this.XCoord);
console.log('YCoord', this.YCoord);
window.addEventListener('mousemove', this.initHandleMouseMove);
},
initHandleMouseMove: function(event) {
this.XCoord = event.clientX;
this.YCoord = event.clientY;
console.log('XCoord', this.XCoord);
console.log('YCoord', this.YCoord);
},
initHandleMouseup: function() {
window.removeEventListener('mousemove', this.initHandleMouseMove);
}
}
});
.chart {
position: relative;
border-radius: 10px;
padding: 27px 10px 10px 10px;
background-color: #45788b;
box-sizing: border-box;
cursor: move;
}
.chart .chartContent {
position: relative;
top: 0;
left: 0;
height: 100%;
width: 100%;
margin: 0 0 0 0;
background-color: #2f2c8b;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id='app'></div>
To see the different between mouseout/mouseover vs mouseenter/mouseleave events see this demo (taken from jQuery documentation) :
var i = 0;
$("div.overout")
.mouseout(function() {
$("p", this).first().text("mouse out");
$("p", this).last().text(++i);
})
.mouseover(function() {
$("p", this).first().text("mouse over");
});
var n = 0;
$("div.enterleave")
.on("mouseenter", function() {
$("p", this).first().text("mouse enter");
})
.on("mouseleave", function() {
$("p", this).first().text("mouse leave");
$("p", this).last().text(++n);
});
div.out {
width: 40%;
height: 120px;
margin: 0 15px;
background-color: #d6edfc;
float: left;
}
div.in {
width: 60%;
height: 60%;
background-color: #fc0;
margin: 10px auto;
}
p {
line-height: 1em;
margin: 0;
padding: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="out overout">
<p>move your mouse</p>
<div class="in overout">
<p>move your mouse</p>
<p>0</p>
</div>
<p>0</p>
</div>
<div class="out enterleave">
<p>move your mouse</p>
<div class="in enterleave">
<p>move your mouse</p>
<p>0</p>
</div>
<p>0</p>
</div>
Actually, I am trying to make a sub-menu where user hovers on the first menu its child list should appear one after one and same on the other menu.
I think it is working fine just a minor problem. I am going to the 2nd or 3rd menu before the complete appearing of the first menu's child. 2nd and 3rd are working fine but again if I hover on the first menu it still shows the remaining list (child) which was left to appear.
(function($) {
$.fn.animateOneByOne = function(params) {
params = $.extend({
css: '',
duration: 700,
interval: 300,
order: 'ASC',
callback: ''
}, params);
if (params.order == 'ASC') {
elements = $(this);
} else {
elements = $(this).get().reverse();
}
count = $(this).length - 1;
$(elements).each(function(id) {
setTimeout(function(element) {
if (id == count) {
$(element).animate(params.css, params.duration, params.callback);
} else {
$(element).animate(params.css, params.duration);
}
}, id * (params.interval + params.duration), $(this));
});
};
})(jQuery);
$('.srvs_dropdown').hover(function() {
$(this).find("ul li").animateOneByOne({
css: {
opacity: '1'
},
duration: 450,
interval: 100
});
return false;
},
function() {
$(this).find("ul li").css("opacity", 0);
});
.srvs_dropdown li {
opacity: 0;
}
a {
color: #fff;
}
.pi-mm-list {
padding-left: 20px;
background-color: #09142D;
width: 250px;
color: #fff;
}
.pi-mm-list li ul {
display: none;
position: absolute;
left: 180px;
width: 234px;
padding-top: 7px;
background-color: #09142D;
z-index: 999;
}
.pi-mm-list li:hover ul {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="pi-mm-list">
<li class="srvs_dropdown">Network Security
<ul>
<li>Firewall and VPN</li>
<li>Web Security</li>
<li>Application Security</li>
<li>Threat Detection & Response</li>
<li>Data Leakage Prevention</li>
<li>IPS</li>
</ul>
</li>
<li class="srvs_dropdown">Endpoint Security
<ul>
<li>Antivirus</li>
<li>DLP</li>
</ul>
</li>
<li class="srvs_dropdown">Wireless Security
<ul>
<li>Access Point</li>
<li>Controller</li>
</ul>
</li>
</ul>
As far as I have understood or observed your question and code, looks like it only works correctly when you hover over all links for the first time top to bottom but once you reach the last menu item in the first block and start hovering in reverse from bottom to top you will see that the submenu links start appearing in randomly, problem is the delay that you have used you just need a small fix i.e incremental delay which you were missing. The code below it works as you expect, observe the difference in the $(elements).each(function(id) { just replace the setTimeOut with delay and add the increment there and watch the difference, you can remove the interval param too see below code and working example, hope it solves the problem.
(function($) {
$.fn.animateOneByOne = function(params) {
params = $.extend({
css: '',
duration: 700,
order: 'ASC',
callback: ''
}, params);
if (params.order == 'ASC') {
elements = $(this);
} else {
elements = $(this).get().reverse();
}
count = $(this).length - 1;
$(elements).each(function(id) {
let isLastLi = id == count;
console.log('animate', id);
(isLastLi) ? $(this).delay((id + 1) * params.duration).animate(params.css, 0, params.callback): $(this).delay((id + 1) * params.duration).animate(params.css, 0);
});
};
})(jQuery);
$('.srvs_dropdown').hover(function() {
console.log('here');
$(this).find("ul li").animateOneByOne({
css: {
opacity: '1'
},
duration: 400
});
return false;
},
function() {
$(this).find("ul li").stop().css("opacity", 0);
});
.srvs_dropdown li {
opacity: 0;
}
a {
color: #fff;
}
.pi-mm-list {
padding-left: 20px;
background-color: #09142D;
width: 250px;
color: #fff;
}
.pi-mm-list li ul {
display: none;
position: absolute;
left: 180px;
width: 234px;
padding-top: 7px;
background-color: #09142D;
z-index: 999;
}
.pi-mm-list li:hover ul {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="pi-mm-list">
<li class="srvs_dropdown">Network Security
<ul>
<li>Firewall and VPN</li>
<li>Web Security</li>
<li>Application Security</li>
<li>Threat Detection & Response</li>
<li>Data Leakage Prevention</li>
<li>IPS</li>
</ul>
</li>
<li class="srvs_dropdown">Endpoint Security
<ul>
<li>Antivirus</li>
<li>DLP</li>
</ul>
</li>
<li class="srvs_dropdown">Wireless Security
<ul>
<li>Access Point</li>
<li>Controller</li>
</ul>
</li>
</ul>
The main idea is to cancel timed-out function when it doesn't need to execute. It looks that out part in .hover(in, out) is the best place to do it. But first we need a list of setTimeout handlers which are generated in the in part. Something like this.
(function($) {
$.fn.animateOneByOne = function(params) {
params = $.extend({
css: '',
duration: 700,
interval: 300,
order: 'ASC',
callback: ''
}, params);
if (params.order == 'ASC') {
elements = $(this);
} else {
elements = $(this).get().reverse();
}
count = $(this).length - 1;
var handlers = [];
$(elements).each(function(id) {
var handle = setTimeout(function(element) {
if (id == count) {
$(element).animate(params.css, params.duration, params.callback);
} else {
$(element).animate(params.css, params.duration);
}
}, id * (params.interval + params.duration), $(this));
handlers.push(handle);
});
return handlers;
};
})(jQuery);
$('.srvs_dropdown').hover(function() {
$(this).data('handler',
$(this).find("ul li").animateOneByOne({//returns the list of handlers
css: {
opacity: '1'
},
duration: 450,
interval: 100
}));
return false;
},
function() {
$(this).data('handler').forEach(function(handle) {
clearTimeout(handle); //cancel setTimeout if it didn't start yet
});
$(this).find("ul li").css("opacity", 0);
});
.srvs_dropdown li {
opacity: 0;
}
.pi-mm-list {
padding-left: 20px;
}
.pi-mm-list li ul {
display: none;
position: absolute;
left: 180px;
width: 234px;
padding-top: 7px;
background: #09142D;
z-index: 999;
}
.pi-mm-list li:hover ul {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="pi-mm-list">
<li class="srvs_dropdown">Network Security
<ul>
<li>Firewall and VPN</li>
<li>Web Security</li>
<li>Application Security</li>
<li>Threat Detection & Response</li>
<li>Data Leakage Prevention</li>
<li>IPS</li>
</ul>
</li>
<li class="srvs_dropdown">Endpoint Security
<ul>
<li>Antivirus</li>
<li>DLP</li>
</ul>
</li>
<li class="srvs_dropdown">Wireless Security
<ul>
<li>Access Point</li>
<li>Controller</li>
</ul>
</li>
</ul>
Hello I have problems with JS clients slider on website.
I want to stop it while mouseover and resume while mouseleft. I have searched and checked the code but I don't know why it still doesn't work, could somebody help me?
$(function(){
var $clientcarousel = $('#clients-list');
var clients = $clientcarousel.children().length;
var clientwidth = (clients * 400); // 140px width for each client item
$clientcarousel.css('width',clientwidth);
var rotating = true;
var clientspeed = 0;
var seeclients = setInterval(rotateClients, clientspeed);
function rotateClients() {
if(rotating != false) {
var $first = $('#clients-list li:first');
$first.animate({ 'margin-left': '-220px' }, 5000, "linear", function() {
$first.remove().css({ 'margin-left': '0px' });
$('#clients-list li:last').after($first);
});
}
}
});
$(document).on({
mouseover: function(){
rotating = false; // turn off rotation when hovering
},
mouseleave: function(){
rotating = true;
}
}, '#clients');
Please have a look at this approach:
$(function() {
var $clientcarousel = $('#clients-list');
var clients = $clientcarousel.children().length;
var clientwidth = (clients * 400); // 140px width for each client item
$clientcarousel.css('width', clientwidth);
var rotating = true;
var clientspeed = 0;
var seeclients = setInterval(rotateClients, clientspeed);
function rotateClients() {
if (rotating != false) {
var $first = $('#clients-list li:first');
$first.animate({
'margin-left': '-220px'
}, 5000, "linear", function() {
$first.remove().css({
'margin-left': '0px'
});
$('#clients-list li:last').after($first);
});
} else {
$('#clients-list li').stop();
}
}
$(document).on({
mouseenter: function(){
rotating = false; // turn off rotation when hovering
},
mouseleave: function(){
rotating = true;
}
}, '.clients');
});
/*Logo carousel*/
.clients {
display: block;
margin-left: auto;
margin-right: auto;
max-height: 20%;
}
.clients .clients-wrap {
display: block;
max-width: 100%;
margin: 0 auto;
overflow: hidden;
}
.clients .clients-wrap ul {
display: block;
list-style: none;
position: relative;
margin-left: auto;
margin-right: auto;
}
.clients .clients-wrap ul li {
display: block;
float: left;
position: relative;
width: 220px;
height: 60px;
line-height: 60px;
text-align: center;
}
.clients .clients-wrap ul li img {
vertical-align: middle;
max-width: 100%;
max-height: 100%;
-webkit-transition: 0 linear left;
-moz-transition: 0 linear left;
transition: 0 linear left;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)";
filter: alpha(opacity=40);
filter: grayscale(100%);
opacity: 0.40;
}
.clients .clients-wrap ul li img:hover {
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
filter: alpha(opacity=100);
filter: grayscale(0%);
opacity: 1.0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div class="clients">
<p></p>
<div class="clients-wrap">
<ul id="clients-list" class="clearfix">
<li>
<img src="http://iconshow.me/media/images/logo/brand-logo-icon/png/256/cocacola-256.png">
</li>
<li>
<img src="img/logos/2.png">
</li>
<li>
<img src="img/logos/3.png">
</li>
<li>
<img src="img/logos/4.png">
</li>
<li>
<img src="img/logos/5.png">
</li>
<li>
<img src="img/logos/6.png">
</li>
<li>
<img src="img/logos/7.png">
</li>
<li>
<img src="img/logos/8.png">
</li>
<li>
<img src="img/logos/9.png">
</li>
<li>
<img src="img/logos/10.png">
</li>
<li>
<img src="img/logos/11.png">
</li>
<li>
<img src="img/logos/12.png">
</li>
<li>
<img src="img/logos/13.png">
</li>
<li>
<img src="img/logos/14.png">
</li>
<li>
<img src="img/logos/15.png">
</li>
</ul>
</div>
<!-- #end .clients-wrap -->
</div>
Simple jQuery carousel
$(window).on("load", makeCarousel);
function makeCarousel() {
var carousel = $('.carousel ul'),
interval = $(carousel).parent().data("interval") * 1000,
speed = $(carousel).parent().data("speed") * 1000,
count = $(carousel).children().length,
width = $(carousel).find("img:first").width(),
id, moveIt;
$(carousel)
.css({
width: count * width,
position: "relative",
margin: 0,
padding: 0,
listStyle: "none"
})
.parent().css({ width: width, overflow: "hidden" })
.animate({opacity: 1}, 250)
.on("mouseover", function() { clearInterval(id) })
.on("mouseout", function() { moveIt() })
.find("li").css({ float: "left" })
.find("img").css({ verticalAlign: "bottom" });
(moveIt = function() {
id = setInterval(function() {
$(carousel).animate({left: -width}, speed, function() {
$(this).css({left: 0});
$(this).children(":last").after($(this).children(":first"));
});
}, interval + speed);
})();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="carousel" data-interval="1" data-speed="0.6" style="opacity:0">
<ul>
<li><img src='http://placehold.it/350x200/111111?text=First Slide'></li>
<li><img src='http://placehold.it/350x200/444444?text=Second Slide'></li>
<li><img src='http://placehold.it/350x200/777777?text=Third Slide'></li>
<li><img src='http://placehold.it/350x200/aaaaaa?text=Fourth Slide'></li>
</ul>
</div>