Sapinder Singh
Sapinder Singh

Reputation: 351

changing position relative to mouse pointer

I looked for many similar question but couldn't solve my issue. Here I have pasted only a single list item out of my code. I need to create a span on mousemove event over the list item, and set its left-offset from its parent as the mouse moves. As I haven't ever tried any such thing, I experimented a lot with the code to get to this-

document.querySelector("li a").addEventListener("mousemove",(event)=> {

			let span;
			let alreadyHasSpan =    event.target.hasChildNodes().length > 1; //default length=1

			if(!alreadyHasSpan) {
				span = $(`<span class="a-effect"></span>`);
				span.appendTo(event.target);
			}

			let targetLeftPos = event.target.getBoundingClientRect().left;

				span.css("left",`${event.clientX-targetLeftPos}px`);


			$(this).mouseleave(function () { 
				span.remove();
			});
}, false);
a {
  position: relative;
}
.a-effect {
	position: absolute; left: 0;
	height: 100%;
	width: 2%;
	background: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<li class="nav-item active">
		<a href="/" class="nav-link">Product</a>	
</li>

On my browser, the span moves but with trailing signs behind it-

Apart from the trailing signs, it oftens misses to show the span. On this question's snippets, it's even worse to show the issue.

What's the issue and how could I fix it?

Upvotes: 0

Views: 1231

Answers (2)

Lian
Lian

Reputation: 2357

As per your question, the issue is that you're adding a new span everytime the mouse moves. I am guessing you only want to add it when mouse enters, and remove it once the mouse leaves.

I have tried to keep your code as much as possible and change only what is causing your issue.

document.querySelector("li a").addEventListener("mouseenter", (event) => {

  let span;
  let alreadyHasSpan = event.target.childNodes.length > 1; //default length=1

  if (!alreadyHasSpan) {
    span = $(`<span class="a-effect"></span>`);
    span.appendTo(event.target);
  }
});

document.querySelector("li a").addEventListener("mousemove", (event) => {
  let targetLeftPos = event.target.getBoundingClientRect().left;
  if (event.target.childNodes.length > 1) {
    let span = event.target.childNodes[1];
    $(span).css("left", `${event.clientX-targetLeftPos}px`);
  }
});

document.querySelector("li a").addEventListener("mouseleave", (event) => {
  if (event.target.childNodes.length > 1) {
    let span = event.target.childNodes[1];
    span.remove();
  }
});
a {
  position: relative;
}

.a-effect {
  position: absolute;
  left: 0;
  height: 100%;
  width: 2%;
  background: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<li class="nav-item active">
  <a href="/" class="nav-link">Product</a>
</li>

Upvotes: 1

Lapskaus
Lapskaus

Reputation: 1721

I am not 100% sure where you want to place your span element but there are some problems in your code that i would correct first. The placement of the element is relatively easy to change then.

Firstly, you append the span element in a mousemove function and them check everytime that event triggers, if the span is already there. Change that to use the mouseenter event for the span creation. Secondly, you add a new mouseleave handler for your link evetytime you move your mouse. Same as before, create that handler outside of your mousemove event.

Regarding the position of your elememt, I am not sure where you expect it to appear/follow your mouse but you can easily adapt the offsetX and offsetY variables in my moveSpan() function to adapt it to your needs.

Keep in mind when you are positioning the element, that the calculation is based off of the position of your a element.

function moveSpan( e ) {
	let $el = $(e.target);
	let xPos = e.pageX;
  let yPos = e.pageY;
  let offsetX = $el.width() / 2;
  let offsetY = $el.height() / 2;
  let $span = $el.find('span');
 	$span.css({
    'left': (xPos - offsetX) + 'px',
    'top': (yPos - offsetY) + 'px'
  });
}

$('li a').on('mouseenter', function( e ) {
	let span = $('<span />').addClass('a-effect');
  $(this).append( span );
  moveSpan( e );
}).on('mousemove', function( e ) {
	moveSpan( e );
}).on('mouseleave', function( e ) {
	$(this).find('span').remove();
});
ul {
  list-style-type: none;
}
a {
  position: relative;
}

.a-effect {
  position: absolute;
  height: 100%;
  width: 10px;
  background: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
  <li class="nav-item active">
    <a href="/" class="nav-link">Product</a>
  </li>
</ul>

Upvotes: 1

Related Questions