I need to swap (change) the image in img tag after hover and click.
I'm not good in javascript so i need help.
If some image is active (clicked) and I click on next image in menu so other images must be change to default.
<ul id="ourteam">
<li><a data-target="#user1" class="active"><img src="/img/avatars/avatar1.png" data-other-src="/img/avatars/avatar1h.png" /></a></li>
<li><a data-target="#user2"><img src="/img/avatars/avatar_t.png" /></a></li>
<li><a data-target="#user3"><img src="/img/avatars/avatar3.png" data-other-src="/img/avatars/avatar3h.png" /></a></li>
<li><a data-target="#user4"><img src="/img/avatars/avatar4.png" data-other-src="/img/avatars/avatar4h.png" /></a></li>
</ul>
add onclick to the anchor
function set_anch_image(anch) {
var imgs = document.getElementById("ourteam").getElementsByTagName("img");
for(var i=0;imgs.length;i++) hold[i].src = "avatar"+(i+1)+".png" ;
anch.getElementsByTagName("img")[0].src = "avatar_t.png" ;
}
You should definitely be using CSS to change the image on hover. Not to mention the fact that you can add a class on hover or click to achieve the same effect using a combination of CSS and JavaScript. However, if you need to accomplish using JavaScript alone, I would recommend using jQuery or another library that has these methods and many others already built-in. Especially if you are not so well versed in plain JavaScript.
CSS
This option removes the need for the image tag completely. In order to ensure that your image is displayed properly you will need to provide dimension to your LI elements within the CSS and also make the A element display: block.
#ourteam li a { display: block; }
#ourteam li:nth-child(1) a { background: url('/img/avatars/avatar1.png'); }
#ourteam li:hover:nth-child(1) a { background: url('/img/avatars/avatar11.png'); }
#ourteam li:nth-child(2) a { background: url('/img/avatars/avatar_t.png'); }
#ourteam li:nth-child(3) a { background: url('/img/avatars/avatar3.png'); }
#ourteam li:hover:nth-child(3) a { background: url('/img/avatars/avatar3h.png'); }
#ourteam li:nth-child(4) a { background: url('/img/avatars/avatar4.png'); }
#ourteam li:hover:nth-child(4) a { background: url('/img/avatars/avatar4h.png'); }
jQuery
This will handle all 3 events - click, mouse enter and mouse leave. It simply swaps the values of the "src" and your "data-other-src".
$(function(){
$('#ourteam img').on('click mousenter mouseleave', function( e ){
e.preventDefault();
var _this = $(this),
oldSrc = _this.attr('src'),
newSrc = (_this.attr('data-other-src')) ? _this.attr('data-other-src') : oldSrc;
_this.attr('src', newSrc).attr('data-other-src', oldSrc);
});
});
Alternatively, we can use the hover and click events to toggle an active class to either the list item or the a. For this example, let's go with the anchor.
CSS
#ourteam li:nth-child(1) a { background: url('/img/avatars/avatar1.png'); }
#ourteam li:nth-child(1) a.active { background: url('/img/avatars/avatar1h.png'); }
#ourteam li:nth-child(2) a { background: url('/img/avatars/avatar_t.png'); }
#ourteam li:nth-child(2) a.active { background: url('/img/avatars/avatar_t.png'); }
#ourteam li:nth-child(3) a { background: url('/img/avatars/avatar3.png'); }
#ourteam li:nth-child(3) a.active { background: url('/img/avatars/avatar3h.png'); }
#ourteam li:nth-child(4) a { background: url('/img/avatars/avatar4.png'); }
#ourteam li:nth-child(4) a.active { background: url('/img/avatars/avatar4h.png'); }
jQuery
$(function(){
$('#ourteam li a').on('click mousenter mouseleave', function( e ){
e.preventDefault();
$(this).toggleClass('active');
});
});
Related
I built a navbar a few weeks back and just realised I did not set an .active class on it. Now, I built the navbar and the links dynamically in JS and would now like to give whichever one is active the according CSS.
This is how I built the navbar in JS:
let womensNav = document.createElement("ul");
womensNav.classList.add("womensNav");
const el1 = document.createElement("li");
el1.innerHTML = "<a>Jeans</a>";
el1.addEventListener("click", (e) => {
document.location.href =
"https://www.martadolska.com/product-category/women/womens-jeans";
});
womensNav.appendChild(el1);
document.querySelector(".ast-woocommerce-container").appendChild(womensNav);
I have more than one link, but for this purpose I don't need to show it all. So now the goal is to build a generic function that gives the active element within the navbar the according class.
document.querySelectorAll("#womensNav li").forEach(function (ele) {
ele.addEventListener("click", function (e) {
e.preventDefault();
document
.querySelectorAll("#womensNav li a.active")
.forEach((ele) => ele.classList.remove("active"));
ele.parentNode.classList.toggle("active");
});
});
And this is what my CSS looks like:
.womensNav li a:hover {
color: var(--main-text-color);
text-decoration: line-through darkred solid;
}
.womensNav li a::before {
content: "";
position: absolute;
width: 100%;
height: 2px;
bottom: 7px;
left: 0;
background-color: #b22222;
visibility: hidden;
transform: scaleX(0);
transition: all 0.3s ease-in-out 0s;
}
.womensNav li a:hover::before {
visibility: visible;
transform: scaleX(1);
}
.womensNav li a:active::before {
content: "";
position: absolute;
width: 100%;
height: 2px;
bottom: 10px;
left: 0;
background-color: #b22222;
}
// up until this point everything works
.active {
text-decoration: line-through darkred solid;
}
I am guessing there is something missing/not completely right in the second snippet of the JS code since nothing is happening when my link is active. I get the animation that I would like to get, but then it disappears once the user is redirected to that specific link, so you wouldn't know which sub-page you are on.
this is wrong
ele.parentNode.classList.toggle("active");
"ele" is the <li>, you are adding the "active" class to the <ul> via the parentNode, might be better to use the "e" event from the click and use e.target and then try and set the active class on the <a> or use childNode/children to get at your <a>
https://codepen.io/m4rsibar/pen/zyPBoz?editors=0110
I've made a codepen example of the effect I'm going for (I've included the code that creates the effect at the very top of the css section), except I want to do it in javascript. (unless there's a way to fix the issues I'm having with the css version)
The issue: the hover is on the div containing the circular elements, if you hover in the div, and aren't on top of an element they all go out of view.
I'm using the :not selector in css to achieve this and to put it on the parent element is the only way I know how to get this to work, I've tried playing around and changing stuff up, to no avail, so I decided to do this with javascript.
In another codepen I tried to simplify as much as possible to try to achieve the effect I'm going for. I've only gotten thus far:
https://codepen.io/m4rsibar/pen/yGPqZM
as you can see when you leave the box it doesn't go back to the original opacity.
Should I be using classes and toggling them?
let lis= document.querySelectorAll('li')
console.log(lis)
lis.forEach(function(li) {
li.addEventListener("mouseover", function(e) {
lis.forEach(function(li) {
e.target.style.opacity="1";
if(e.target.style.opacity==="1"){
li.style.opacity="0.3";
}else{
li.style.opacity="1";
}
});
})
});
This is a simpler approach using only a line of CSS and no JavaScript. Because opacity: 1 is implicit, we don't have to declare that at all, only styles for the non-hovered state.
li {
list-style: none;
background-color: pink;
margin: 2px;
height: 200px;
width: 200px
}
ul {
display: flex;
}
li:not(:hover) {
opacity: 0.3;
}
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
Update
After your feedback and latest example, I took another stab at it. My goal was avoid the double active class on both the ul and active li. It's not ideal from a performance standpoint, but beyond that, it's more JavaScript and CSS to maintain.
What I came up with is a function that detects if an li is the current target (while the mouse is somewhere inside the ul). If the current target is not an li it means that our ul is active but no children are being hovered. I toggle a class accordingly. I like that everything is stored in the ul and we no longer need any li event tracking.
var ul = document.querySelector('ul');
function boxEnter(e) {
this.classList.add('active');
}
function boxLeave(e) {
this.classList.remove('active');
}
function boxMove(e) {
this.classList.toggle('childrenInactive', e.target.tagName !== 'LI');
}
ul.addEventListener('mousemove', boxMove);
ul.addEventListener('mouseenter', boxEnter);
ul.addEventListener('mouseleave', boxLeave);
li {
list-style: none;
background-image: url('https://source.unsplash.com/collection/1163637/200x200');
border-radius: 50%;
margin: 2px;
height: 200px;
width: 200px;
transition: .3s ease;
cursor: crosshair;
will-change: filter, transform;
}
ul {
display: flex;
flex-wrap: wrap;
}
ul.active li {
opacity: .3;
transform: scale(1.1);
filter: blur(5px);
}
ul li:hover,
ul.active.childrenInactive li {
opacity: 1;
transform: scale(1);
filter: blur(0);
}
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
http://jsfiddle.net/j3reaqsw/
I am having an issue trying to set a class to the active nav item.
I need some help trying to figure out where i am going wrong.
It is some what working but not correctly, it defaults to the menu item which has a sub menu and i can't see where i have gone wrong.
When clicking on say "contact us" for example - the href takes me to the contact page but the active class does not apply and remains on "Products"
What i want to happen is the active class applies to the item that is clicked and not stuck on "products"
Here is JSFiddle https://jsfiddle.net/2yv92roL/
Thanks for help in advance!
Here is HTML:
<nav class="navigation">
<ul class="mainmenu">
<li>Home</li>
<li>Our Philosophy</li>
<li>Products
<ul class="submenu">
<li>Charbonnier Cookware</li>
<li>Charbonnier Dinnerware</li>
<li>Charbonnier Storageware</li>
</ul>
</li>
<li>Contact us</li>
</ul>
</nav>
Here is my CSS:
/* define a fixed width for the entire menu */
.navigation {
width: 150px;
}
/* reset our lists to remove bullet points and padding */
.mainmenu, .submenu {
list-style: none;
padding: 0;
margin: 0;
}
/* make ALL links (main and submenu) have padding and background color */
.mainmenu a {
display: block;
text-decoration: none;
padding: 10px;
}
/* add hover behaviour */
.mainmenu a:hover {
background-color: #C5C5C5;
}
/* when hovering over a .mainmenu item,
display the submenu inside it.
we're changing the submenu's max-height from 0 to 200px;
*/
.mainmenu li:hover .submenu {
display: block;
max-height: 200px;
}
/*
we now overwrite the background-color for .submenu links only.
CSS reads down the page, so code at the bottom will overwrite the code at the top.
*/
/* hover behaviour for links inside .submenu */
.submenu a:hover {
background-color: #C5C5C5;
}
/* this is the initial state of all submenus.
we set it to max-height: 0, and hide the overflowed content.
*/
.submenu {
overflow: hidden;
max-height: 0;
-webkit-transition: all 0.5s ease-out;
}
.navigation ul li .active {
color: #0080A6;
}
Here is my JQuery
$(function() {
var pgurl = window.location.href.substr(window.location.href.lastIndexOf("/")+1);
$(".navigation ul li a").each(function(){
if($(this).attr("href") == pgurl || $(this).attr("href") == '' )
$(this).addClass("active");
})
});
You need to make a couple of changes:
Remove "$(this).attr("href") == ''" from your if condition, this is the reason your "Products" menu is getting the active class by default
Add "$(".navigation ul li a").removeClass("active");" before your each to remove the active class from the previously selected menu
Add "/" to your pgurl so that it matches the href attribute of your menus
Here is the updated code:
$(function () {
var pgurl = "/" + window.location.href.substr(window.location.href.lastIndexOf("/") + 1);
$(".navigation ul li a").removeClass("active");
$(".navigation ul li a")
.each(function() {
if ($(this).attr("href") == pgurl)
$(this).addClass("active");
});
});
Can someone explain me what I'm doing wrong, if you click on the first link(link 1) it opens a menu, if you click on one of the 'li' inside the menu it closes the menu.
If I click on the second link(link 2) it opens a different menu but when I click on one of the 'li' inside the menu nothing happens, and what I am trying to do is to close the menu.
jsfiddle (http://jsfiddle.net/BdhxL/)
The HTML code:
Link 1
<div id="dropMenu">
<ul>
<li>Portfolio</li>
</ul>
</div>
<br><br>
Link 2
<div id="dropMenu">
<ul>
<li>Contact us </li>
</ul>
</div>
The JS code:
$(document).ready(function() {
$("li").click(function()
{
$("#dropMenu").hide("slow");
});
$("a").click(function()
{
$(this).toggleClass("active");
$(this).next("div").stop('true','true').slideToggle("slow");
});
});
#dropMenu {
display: none;
position: relative;
right: 5px;
background: #000;
color: black;
margin:50px -5% 0% -142%;
padding: 0px 0px 0px 10px;
}
#dropMenu a {
display: block;
color: #fff;
text-decoration: none;
padding:10px 6px;
font-weight:400;
border-bottom: solid 1px #fff;
}
The CSS code:
#dropMenu ul {
margin:0;
}
#dropMenu a:hover {
background: #57585A;
}
#dropMenu ul {
list-style:none;
padding:0;
}
You have duplicate ids.$("#dropMenu").hide("slow"); is always targetting first dropMenu. Use $(this) to target current and hide the closest div.Try this:
$(document).ready(function() {
$("li").click(function()
{
$(this).closest("div").hide("slow");
});
$("a").click(function()
{
$(this).toggleClass("active");
$(this).next("div").stop('true','true').slideToggle("slow");
});});
Working Demo
Currently, you're having duplicated id for parent div of your list which is <div id="dropMenu"> , you need to use class instead:
<div class="dropMenu">
then you can use .closest() to target closest matching .dropMenu of clicked li:
$(document).ready(function () {
$("li").click(function () {
$(this).closest(".dropMenu").hide("slow");
});
$("a").click(function () {
$(this).toggleClass("active");
$(this).next("div").stop('true', 'true').slideToggle("slow");
});
});
You also need to change all #dropMenu to .dropMenu in your CSS.
Updated Fiddle
I'm rather new to jQuery and I'm trying to make a cool little menu effect where when the user hovers over a element (#nav li) it will animate to a larger width, which will reveal the full background image. Each of the menu items has a ID to explicitly set a width (since they are all different in size), so #nav1 might be 80px whereas #nav2 is 90px. So I found this: How to get all of the IDs with jQuery? and that helped me to create a array but now I'm having problem figuring out how to insert it into the animation. I figured I would need to do a each or for loop. But like I said I'm rather new to jQuery and am having some problems.
So basically I'd like the variable chgWidth to return the width() of the currently hovered #nav and then I would plug that variable into the animate except I would add 30px for instance, or on the hover off I would subtract 30px.
Any idea? Here is my current code...
$(function(){
var chgWidth = $("#nav [id]").map(function(id) {
return this.id;
});
$.each(chgWidth,function(n,value){
$('#nav li').hover(function() {
$(this).stop(0,1).animate({"width" : chgWidth+"px" });
},
function(){
$(this).stop(0,1).animate({ "width" : chgWidth+"px" });
});
});
Sample HTML
<div id="menu">
<ul id="nav">
<li id="nav1"><a alt="" href="#">home</a></li>
<li id="nav2"><a alt="" href="#">about us</a></li>
<li id="nav3"><a alt="" href="#">weddings & events</a></li>
<li id="nav4"><a alt="" href="#">gallery</a></li>
<li id="nav5"><a alt="" href="#">accolades</a></li>
<li id="nav6"><a alt="" href="#">blog</a></li>
<li id="nav7"><a alt="" href="#">contact us</a></li>
</ul>
</div>
Sample CSS:
#menu { width: 100%; overflow: hidden; padding:0px 0px; background: #ffc4a0;}
#nav { position: relative; left: 50%; float: left;}
#nav li { position: relative; right: 50%; float: left; padding: 0 5px; margin: 0 5px; overflow:hidden; }
#nav1 { width:55px; }
#nav2 { width:80px; }
#nav3 { width:175px; }
#nav4 { width:60px; }
#nav5 { width:85px; }
#nav6 { width:40px; }
#nav7 { width:100px; }
#nav li a { color: #ffffff; text-decoration: none; font: bold 16px Verdana, Arial, Helvetica, sans-serif; }
Based on the answer I got this is what I ended up doing and it seems to work good (Thanks to Joel and krdluzni):
$(function(){
$("#nav [id]").each(function(){
$(this).hover(function() {
$(this).stop(0,1).animate({"width" : "+=30" });
},
function(){
$(this).stop(0,1).animate({ "width" : "-=30" });
});
});
});
jQuery as of a short while ago accepts a += like syntax for widths and other numeric values in animate. See the second last paragraph in the overview (and the examples as well) here: http://docs.jquery.com/Effects/animate#paramsdurationeasingcallback
You don't actually need to get the ids in an array so much as you need to assign an animation to each element in nav that has an id.
Instead of mapping the ids to your chgWidth variable, use each to iterate over the collection of elements and set each one individually.
$(function(){
$("#nav [id]").each(function(){
$(this).hover(function() {
$(this).stop(0,1).animate({"width" : this.id+"px" });
},
function(){
$(this).stop(0,1).animate({ "width" : this.id+"px" });
});
});
});
When you use each to iterate over a collection of elements, the this context is set to the current iterating element.
No each function is required! If a selector returns multiple elements, all of the elements recieve the function chained to them.
This is almost right:
$("li #nav").hover(
function()
{
$(this).stop(0,1).animate({"width" : this.width()+30 });
//save original width somehow
},
function()
{
$(this).stop(0,1).animate({ "width" : this.width()-30 });
//retrieve original width
});
);
You just need to save the widths somehow. Perhaps they can be read from the CSS.