I'm creating a simple hamburger menu and I want to add new className to element when onClick event occurs. This new className should transform the element, but when onClick occurs element dissapears, animation doesn't work. I understand the problem is in classes.line[i] part, but what could be the problem maybe someone can help me here.
link to the example https://repl.it/#RokasSimkus/DelectableFrugalMuse
jsx:
const menu = (props) =>{
let lineArray= ['', '', ''];
let lines= lineArray.map((lineArray, i) => {
return <span key={"classes.line" + i} className={!props.active ? classes.line : classes.line[i]}></span>
});
console.log(props.active);
return(
<>
<div className={!props.active ? classes.hamburger: classes.hamburger}
onClick={props.open}
onMouseOver={props.mouseHover}
onMouseLeave={props.leaveMouseHover}>
{lines}
</div>
</>
)
};
css code:
#media(min-width: 500px){
.hamburger{
display: none;
}
}
.hamburger {
left: 0;
top: 0;
}
.hamburger .line {
display: block;
width: 30px;
height: 2px;
background-color: white;
margin: 8px 0;
transition: all 0.3s ease-in-out;
}
.hamburger:hover {
cursor: pointer;
.line:nth-of-type(1) {
transform: translateX(15px);
width: 40px;
}
}
.hamburger .line1 {
transform: translate(4px, 1px) rotate(45deg);
width: 18px;
}
.hamburger .line2 {
transform: rotate(-45deg);
width: 51px;
}
.hamburger .line3 {
transform: translate(14px, 4px) rotate(45deg);
width: 28px;
transform-origin: bottom right;
}
If I change the line you marked to the following, it works:
return <span key={"classes.line" + i} className={`${classes.line} ${props.active ? `${classes["line" + i]}` : ''}`}></span>
To show anything, your lines need the class .line. To be in the "active" state, they need to add their respective .lineX class to add the transform you want to see. As you need both classes at the same time, you need to put both into the className property, which I've done here by putting them together into a string.
I'd suggest to change your CSS and add an active class to your menu.
The underlying problem is that you need to add multiple classes to your elements at some point. You can do that with string interpolation like I showed above (same would be for adding an active class to .menu) or you could use a module like classnames which does a great job concatenating classes. Thus you could write
return <span key={"classes.line" + i} className={classnames(classes.line, props.active && classes["line" + i])}></span>
I'd still suggest to create an active modifier class on your "root" element of your component, to keep modifiers on the top level and your code a bit more understandable. Here is your modified example.
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>
Any problem with this code it wont show when I tried to click the toggle icon in responsive view in console it says:
navTogglerBtn is null
I tried to look at it but I can't find the problem. Im new in JavaScript. Thank you so much heres my code in JSFiddle code is here
const navTogglerBtn = document.querySelector(".nav-toggler"),
aside = document.querySelector(".aside-menu");
navTogglerBtn.addEventListener("click",() => {
asideSectionTogglerBtn();
})
function asideSectionTogglerBtn() {
aside.classList.toggle("open");
navTogglerBtn.classList.toggle("open");
}
You CSS code is wrong. It's .nav-toggler.open not .nav-toggler .open. And apply some transition to have smooth effect.
.aside-menu .nav-toggler {
display: flex;
left: 30px;
transition: 0.5s;
}
.aside-menu {
left: -270px;
transition: 0.5s;
}
.aside-menu .nav-toggler.open {
left: 300px;
}
.aside-menu.open {
left: 0px;
}
I'm new to JavaScript, and I've included JS at the bottom of my HTML page. I checked the selectors, actions and everything seems to match. However, when I try to use JS functionality nothing seems to happen; as if there is no JS at all.
Tried checking if the selectors and actions are valid. Tried checking if I included the script tags within my tag.
const navBtn = document.getElementById("nav-btn");
const navBar = document.getElementById("navbar");
const navClose = document.getElementById("close");
navBtn.addEventListener("click", () => {
navBar.classList.add("showNav");
});
navClose.addEventListener("click", () => {
navBar.classList.remove("showNav");
});
.showNav {
transform: translateX(0%);
}
.close {
color: var(--mainWhite);
font-size: 2.1rem;
cursor: pointer;
}
.close:hover {
color: var(--mainDark);
padding-left: 0.2rem;
}
Complete project can be found here for more information: https://github.com/aleblok70/website.
Desired result was to include action on click transform: translateX(0); actual results were that nothing happens on click.
You are adding the listener to the element based on an id -
const navClose = document.getElementById("close");
but your styling is based on a class - is this correct?
.close {..}
These need to be the same - so if the id is correct then it should be
#close {
color: var(--mainWhite);
font-size: 2.1rem;
cursor: pointer;
}
#close:hover {
color: var(--mainDark);
padding-left: 0.2rem;
}
I'm relatively new to coding and am running into a particular issue with my website. My homepage has images on it with overlay text hover effect that occurs when a cursor is moved over the image. It works perfectly on desktop, however, not on mobile. I would like for the hover text to appear when the user swipes across the image in any direction. I've done some research and it appears that I should somehow be using jQuery and the touchmove function to make this happen. But I just can't figure it out. I am using Shopify (debut theme) to build my website. Any help will be greatly appreciated!
Here's my CSS for hover event:
//hover effect//
.container {
position: relative;
width: 100%;
}
.image {
display: block;
width: 100%;
height: auto;
}
.overlay {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
height: 99%;
width: 100%;
opacity: 0;
transition: .5s ease;
background-color: #000000;
}
.container:hover .overlay {
opacity: 0.7;
}
.text {
color: white;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 20px;
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
text-align: center;
white-space: pre;
}
Thanks!!!!
You'd need to apply a class with the desired effect to the target element.
You could do it with Jquery, but javascript is perfectly capable to do it on its own.
Something like:
Javascript:
const myTargetElement = document.getElementsByClassName('overlay')[0]; // index to be confirmed
// add hover style
myTargetElement.addEventListener('touchmove', function (e) {
e.target.classList.add('hover'); // or whichever class name you'd like
});
// remove hover style on end
myTargetElement.addEventListener('touchend', function (e) {
e.target.classList.remove('hover'); // or whichever class name you'd like
});
CSS:
.container:hover .overlay,
.overlay.hover {
opacity: 0.7;
}
Note: if you want to target all the elements .overlay on your page with that code, you would need something like:
Javascript:
const myTargetElements = document.getElementsByClassName('overlay');
// convert HTML collection to array
const myTargetElementsArray = [].slice.call(myTargetElements);
myTargetElementsArray.forEach(function (element) {
// add hover style
element.addEventListener('touchmove', function (e) {
e.target.classList.add('hover'); // or whichever class name you'd like
});
// remove hover style on end
element.addEventListener('touchend', function (e) {
e.target.classList.remove('hover'); // or whichever class name you'd like
});
});
so Moustachiste's code works! It had a few syntax errors but I was able to resolve them quickly. Here's the final version:
const myTargetElements = document.getElementsByClassName('overlay');
// convert HTML collection to array
const myTargetElementsArray = [].slice.call(myTargetElements);
myTargetElementsArray.forEach(function (element) {
// add hover style
element.addEventListener('touchmove', function (e) {
e.target.classList.add('hover'); // or whichever class name you'd like
});
// remove hover style on end
element.addEventListener('touchend', function (e) {
e.target.classList.remove('hover'); // or whichever class name you'd like
});
});
Paste the code into your theme.js and adjust the variable names accordingly. Should work for everyone!
Cheers to this guy!
I created arrow images using css.
but the problem is i need to add the .down-arrow class to the div when the accordion opens up.
right now I added one image but not sure how to add the other image.
can you guys tell me how to fix it
providing my code below
.down-arrow {
-ms-transform: rotate(-55deg);
Create an invisible class like this
.invisible{
display:none;
}
And then
var upArrowClassName = 'up-arrow' + (this.props._selected ? '' : ' invisible');
var downArrowClassName = 'down-arrow' + (this.props._selected ? ' invisible' : '');
And then apply these classes to the divs
<div className={upArrowClassName}></div>
<div className={downArrowClassName}></div>
At any given point in time according to the value of this.props._selected one will have the invisible class attached to it and won't be visible.
When an accordion is opened, a new "selected" class is added to the accordion section. Rather than trying to change the class itself, just use this new 'selected' class and change the rotate property on your existing arrow. eg:
.selected .up-arrow {
transform: rotate(-45deg);
}
You can add the same this.props._selected in your Accordion section component as:
var className1 = this.props._selected ? 'down-arrow' : 'up-arrow';
And change the className in render as:
className={className1}
Also make some changes in .down-arrow class as:
.down-arrow {
border-top: .15em solid #0b6997;
border-right: .15em solid #0b6997;
border-bottom: 0;
border-left: 0;
width: .5em;
height: .5em;
-ms-flex-item-align: center;
-ms-grid-row-align: center;
align-self: center;
transition: all .3s ease;
-ms-transform: rotate(-45deg);
transform: rotate(-45deg);
}
Look at the fiddle.