What I want to achieve is to change some property (background-color in the code above) twice from js so that transition would run between them but not from the previous state to the first one. The code above almost never works because timeout is set to zero, it works almost always when it is set at least to 10 and it works always on my machine when I set it to 100. What I also want is to avoid timeouts completely and ether run the code linearly or based on the appropriate event callback (I didn't find any useful so far).
Here is an example (also on jsFiddle):
var outter = document.getElementById('outter');
var test = document.getElementById('test');
test.onclick = function() {
outter.removeChild(test);
test.style.backgroundColor = 'green'
outter.appendChild(test);
setTimeout(function() {
test.style.backgroundColor = 'red'
}, 0);
}
#test {
position: fixed;
left: 2em;
right: 2em;
top: 2em;
bottom: 2em;
background-color:red;
transition-duration: 2s
}
<div id=outter>
<div id=test></div>
</div>
Without timeouts:
var outter = document.getElementById('outter');
var test = document.getElementById('test');
test.onmousedown= function() {
test.style.transitionDuration = "0s";
test.style.backgroundColor = 'green';
};
test.onmouseup= function() {
test.style.transitionDuration = "2s";
test.style.backgroundColor = 'red';
};
#test {
position: fixed;
left: 2em;
right: 2em;
top: 2em;
bottom: 2em;
background-color:red;
}
<div id=outter>
<div id=test></div>
</div>
I managed to do it using a very short transition when going green and using transitionend handlers (which, sadly, still require vendor prefixes — yeesh).
The following works for me with Firefox, Chrome, and IE11. (I should note that you don't have to use classes, I just prefer to keep styling in the CSS; you could use outter.style.transitionDuration = "2s"; and such.)
var outter = document.getElementById('outter');
var test = document.getElementById('test');
function onTransition(element, handler, add) {
var method = (add ? "add" : "remove") + "EventListener";
element[method]("transitionend", handler, false);
element[method]("mozTransitionEnd", handler, false);
element[method]("webkitTransitionEnd", handler, false);
}
test.onclick = function() {
// If we're running...
if (outter.classList.contains("green")) {
// ...reset
onTransition(outter, greenToRed, false);
onTransition(outter, redDone, false);
outter.classList.remove("green", "red");
}
onTransition(outter, greenToRed, true);
outter.classList.add("green");
};
function greenToRed() {
onTransition(outter, greenToRed, false);
onTransition(outter, redDone, true);
outter.classList.add("red");
}
function redDone() {
onTransition(outter, redDone, false);
outter.classList.remove("green", "red");
}
#test {
position: fixed;
left: 2em;
right: 2em;
top: 2em;
bottom: 2em;
background-color: red;
}
.green #test {
background-color: green;
transition-duration: 0.0001s;
}
.red #test {
transition-duration: 2s;
background-color: red;
}
<div id=outter>
<div id=test></div>
</div>
The above is just proof-of-concept, of course; it can be refined and cleaned up a fair bit.
Related
Is there anyway of removing an if statement after it has been fired once?
I have a menu container that shows on page load and want it so when the user scrolls 1px it slides away. I don't though want a the browser constantly tracking a scrollTop() method because of the performance hit from this.
What's the best way to remove or cancel an if statement after it has been used once?
The code is below and I have a codepen here: http://codepen.io/emilychews/pen/evbzMQ
jQuery(document).ready(function($) {
$(window).scroll(function() {
if ($(document).scrollTop() > 1) {
$('.menubox').css('left', '-25%');
}
});
$('.mybutton').on('click', function() {
$('.menubox').css('left', '0%');
});
});
body {
margin: 0;
padding: 0;
height: 200vh;
}
.menubox {
top: 100;
position: fixed;
width: 20%;
height: 100%;
background: red;
padding: 10px;
color: white;
transition: all 1s;
}
.mybutton {
position: fixed;
left: 40%;
top: 50px;
padding: 5px 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="menubox">Menu Box</div>
<button class="mybutton">menu</button>
Sounds like you actually have two conditions. One is based on the scroll position, the other is based on some state to be tracked. So just add a variable to track that state. Maybe something like:
var scrolled = false;
$(window).scroll(function() {
if ( !scrolled && $(document).scrollTop() > 1) { // check the state
$('.menubox').css('left', '-25%');
scrolled = true; // update the state
}
});
$('.mybutton').on('click', function() {
$('.menubox').css('left', '0%');
scrolled = false; // don't forget to reset the state
});
You can call off() within the if statement to remove the event handler.
Also note that if you're concerned about performance you can debounce the event handler so that it only executes the logic once scrolling stops for N ms:
var scrollTimer;
$(window).scroll(function() {
clearTimeout(scrollTimer)
scrollTimer = setTimeout(function() {
if ($(document).scrollTop() > 1) {
$('.menubox').css('left', '-25%');
$(window).off('scroll');
}
}, 150);
});
I am working on a video player that launches a video into an iframe within a div overlay. I want to avoid repetetive code such as onclick=() in every link, and want to avoid external libraries such as jQuery, because jQuery produces an unpleasant flickering screen when my video window is launched.
My problem is that with my work so far, only the first link opens the video overlay. I (somewhat) understand that the [0] indicates the first element in an array. Can an array contain an infinite numerical range, or is there a better way to accomplish my goal here? There will potentially be thousands of videos in these galleries, so listing them one at a time in my script is not practical.
I am still struggling to learn, so a working example would be greatly appreciated. Thanks
My work so far
https://jsfiddle.net/4oomb9rt/
example code
<!doctype html>
<html>
<head>
<title>Video Overlay</title>
<style>
body {
margin: 0;
font-family: arial;
}
#vidPlayer {
height: 100%;
width: 100%;
position: fixed;
z-index: 1;
top: 0;
left: 0;
background-color: #000;
overflow: hidden;
transition: 0.5s;
display: none;
color: white;
}
.closebtn {
position: absolute;
top: 7px;
right: 7px;
font-size: 50px;
}
.openbtn {
font-size: 30px;
}
.openbtn, .closebtn {
max-height: 48px;
max-width: 48px;
min-height: 48px;
min-width: 48px;
border-radius: 7px;
line-height: 12px;
}
.vidContent {
width: 100%;
text-align: center;
font-size: 32px;
}
</style>
</head>
<body>
<div id="vidPlayer">
<button class="closebtn">×</button>
<div class="vidContent">vidplayer content</div>
</div>
<button class="openbtn">☰</button>
<button class="openbtn">☰</button>
<button class="openbtn">☰</button>
<script>
function openNav() {
document.getElementById("vidPlayer").style.display = "block";
}
function closeNav() {
document.getElementById("vidPlayer").style.display = "none";
}
var opener = document.getElementsByClassName('openbtn')[0];
opener.addEventListener("click", function(e) {
openNav();
}, false);
var closer = document.getElementsByClassName('closebtn')[0];
closer.addEventListener("click", function(e) {
closeNav();
}, false);
</script>
</body>
</html>
You can iterate over element using ClassName and assign event listener.
for(var i=0;i<document.getElementsByClassName("openbtn").length;i++){
document.getElementsByClassName("openbtn")[i].addEventListener("click", function(e) {
openNav();
}, false);
}
Demo : https://jsfiddle.net/tj23hy3h/
You are on the right track. You want to make a few minor changes to your javascript.
var openers = document.getElementsByClassName('openbtn');
for(var i=0; i<openers.length; i++) {
openers[i].addEventListener("click", function(e) {
openNav();
}, false);
}
var closers = document.getElementsByClassName('closebtn');
for(var i=0; i<closers.length; i++) {
closers[i].addEventListener("click", function(e) {
closeNav();
}, false);
}
by iterating through all of your openers or closers you can add the listener to each one.
What you're problem is that you'll have to add you event listener to all of the elements of that type so something like this would work:
var opener = document.querySelectorAll('.openbtn');
Array.from(opener).foreach(function(opener_single){
opener_single.addEventListener("click", openNav, false);
});
and then the same theory for the closer elements.
what I'm doing here is I'm getting all elements with the class name of openbutton then looping through them in the loop i am then applying the click event listener in which runs the openNav function.
I am having issue with the mouseenter and the mouseleave event in javascript. The strange thing is that the code works if you substitute these 2 events with click or dblclick events. Hope you can help me here.
PS: I'm using chrome.
don't know how to make js work on fiddle... for now
here's the code:
https://jsfiddle.net/frempong69/t7du0kte/
(function() {
window.onload = function() {
var box = document.getElementsByClassName("box")[0];
var change = function() {
box.style.backgroundColor = "green";
};
var normal = function() {
box.style.backgroundColor = "blue";
}
addEventListener("click", change, false);
addEventListener("mouseleave", normal, false);
};
}());
You are adding the mouseleave/mouseenter handlers to the window object. The click handler works because it bubbles to the window object, but the mouseenter and mouseleave events doesn't bubble so the listeners attached to the window object won't get triggered
You need add the listerns to the box element
(function() {
window.onload = function() {
var box = document.getElementsByClassName("box")[0];
var change = function() {
box.style.backgroundColor = "green";
};
var normal = function() {
box.style.backgroundColor = "blue";
}
box.addEventListener("mouseenter", change, false);
box.addEventListener("mouseleave", normal, false);
};
}());
.box {
background-color: red;
width: 400px;
height: 200px;
margin: 50px auto;
position: relative;
}
.box:after {
content: " ";
width: 0px;
height: 0px;
border-top: 100px solid transparent;
border-right: 100px solid transparent;
border-bottom: 100px solid transparent;
border-left: 100px solid red;
position: absolute;
left: 100%;
top: 50%;
margin-top: -100px
}
<div class="box">
</div>
You can simply do like this
box.onmouseenter = change;
box.mouseleave = normal;
You must change
addEventListener("click", change, false);
addEventListener("mouseleave", normal, false);
with this
box.addEventListener("click", change, false);
box.addEventListener("mouseout", normal, false);
you just use this
<div class="box" onmouseover="style.background='green'" onmouseout="style.background='red'">
</div>
its work
To get a better idea what i'm doing look here for my previous code that i try to make a little better >>Codepen
I want to have an array that i fill up with all the id's that i try to animate and with one function toggle the classes .open .closed on every id in the array.
so on an click add .open to #Hamburger, #Navigation, #Black-filter. and one second click remove .open and add .closed for those id's.
because i'm still learning javascript i want it to work in vanilla javascript so i understand the basics before im going on with jquery.
var hamburger = document.getElementById('Hamburger');
var navigation = document.getElementById('Navigation');
var blackFilter = document.getElementById('Black-filter');
var isOpen = true; // true or false
var animation = [h, s, b]; // #H #S #B
var open = "open"; // .open
var closed = "closed"; // .closed
function trigger() {
if (isOpen === true) {
animation.classList.add(open); // add .open to all id's
animation.classList.remove(closed); // remove .closed from all id's
} else {
animation.classList.add(closed);
animation.classList.remove(open);
}
isOpen = !isOpen; // toggles true to false
}
hamburger.addEventListener('click', trigger, false); // onclick toggle class
blackFilter.addEventListener('click', trigger, false); // onclick toggle class
body {
width: 100%;
}
#Hamburger {
height: 100px;
background: red;
width: 100px;
}
#Hamburger.open {
opacity: 0.5;
}
#Hamburger.closed {
opacity: 1;
}
#Navigation {
height: 100px;
background: blue;
width: 100px;
}
#Navigation.open {
opacity: 0.5;
}
#Navigation.closed {
opacity: 1;
}
#Black-filter {
height: 100px;
background: green;
width: 100px;
}
#Black-filter.open {
opacity: 0.5;
}
#Black-filter.closed {
opacity: 1;
}
<body>
<div id="Hamburger"></div>
<div id="Navigation"></div>
<div id="Black-filter"></div>
</body>
What you are looking for is:
var isOpen = true;
var hamburger = document.getElementById('Hamburger');
var navigation = document.getElementById('Navigation');
var blackFilter = document.getElementById('Black-filter');
var animatable = [hamburger, navigation, blackFilter];
var openClass = "open"; // .open
var closedClass = "closed"; // .closed
function trigger() {
if (isOpen) {
animatable.forEach(function (element) {
element.classList.add(openClass);
element.classList.remove(closedClass);
});
} else {
animatable.forEach(function (element) {
element.classList.add(closedClass);
element.classList.remove(openClass);
});
}
isOpen = !isOpen;
}
hamburger.addEventListener('click', trigger, false);
blackFilter.addEventListener('click', trigger, false);
Demo
There are a few things that need improvement.
First of all you are naming you variables rather poorly. Which is actually already one of your problems, first you say that
var b = document.getElementById('B');
and then later
var b = "closed";
So this needs to be fixed, use variable names that are descriptive so you will know what you are talking about when.
Last but not least you are trying to change the elements of that array a, not the array itself. So you need to access the elements by themselves, set their classes and then you are good to go e.g.:
for( var index in a ) {
if ( open === true ) {
a[index].classList.add(b);
a[index].classList.remove(c);
} else {
a[index].classList.add(c);
a[index].classList.remove(b);
}
open = !open;
Firstly ou don't need "open" AND "close" classes, only one would clearly simplify your code (and there is the "default" state).
Then, add a class for all your buttons, the easily manipulate them in JS and CSS (here the class ".btn");
// Directly get on array (a NodeList more precisely)
var buttons = document.getElementsByClassName('btn');
function toggleClass() {
// Loop to add or remove (toggle) the the '.open' class
for (var i=0; i<buttons.length; i++) {
buttons[i].classList.toggle('open');
}
}
// Loop to add event listener to all buttons
for (var i=0; i<buttons.length; i++) {
buttons[i].addEventListener('click', toggleClass, false);
}
.btn {
height: 100px;
width: 100px;
}
.btn.open {
opacity: 0.5;
}
#Hamburger { background: red; }
#Navigation { background: blue; }
#Black-filter { background: green; }
<div id="Hamburger" class="btn"></div>
<div id="Navigation" class="btn"></div>
<div id="Black-filter" class="btn"></div>
This is already way simpler. But you should have a parent element holding the opened/closes state, so you wouldn't loop in an array.
// Only need to manipulate one DOM node
var menu = document.getElementById('menu');
function toggleClass() {
menu.classList.toggle('open');
}
menu.addEventListener('click', toggleClass, false);
body {
width: 100%;
}
.btn {
height: 100px;
width: 100px;
}
.menu.open > .btn {
opacity: 0.5;
}
#Hamburger { background: red; }
#Navigation { background: blue; }
#Black-filter { background: green; }
<div class="menu" id="menu">
<div id="Hamburger" class="btn"></div>
<div id="Navigation" class="btn"></div>
<div id="Black-filter" class="btn"
</div>
Your event listener gets the event as the 1st argument. Use it to decide what to do:
function trigger(event) {// use event.target ... }
I have created the following code that on page load adds opacity: 1 to all divs on the page. In doing so all the images are seen on pageload, but I want each to fade in slowly and after one has completely loaded/is visible I want the 2nd image to load exactly the same then followed by the third.
How can I accomplish this via the code below; what needs to be changed/added? Please note it must use pure Javascript; no CSS3 or jQuery as the proprietary framework I'm working in requires pure JS.
var imageOne = document.getElementById('imageOne');
var imageTwo = document.getElementById('imageTwo');
var imageThr = document.getElementById('imageThr');
function fadeIn() {
imageOne.style.opacity = '1';
imageTwo.style.opacity = '1';
imageThr.style.opacity = '1';
}
#imageOne {
background: url('https://thingiverse-production-new.s3.amazonaws.com/renders/16/04/2d/b5/ed/smiley_face_thumb_small.jpg');
background-repeat: no-repeat;
width: 50px;
height: 50px;
margin-right: 20px;
float: left;
opacity: 0;
}
#imageTwo {
background: url('http://www.mpaart.org/wp-content/uploads/2015/07/twitter-logo-round-50x50.png');
background-repeat: no-repeat;
width: 50px;
height: 50px;
margin-right: 20px;
float: left;
opacity: 0;
}
#imageThr {
background: url('http://orig08.deviantart.net/24c1/f/2009/238/d/8/small_50x50__png_clock_pic_by_counter_countdown_ip.png');
background-repeat: no-repeat;
width: 50px;
height: 50px;
float: left;
opacity: 0;
}
<body onload="fadeIn()">
<div id="wrapper">
<div id="imageOne"></div>
<div id="imageTwo"></div>
<div id="imageThr"></div>
</div>
</body>
You can use CSS transitions, which is faster and won't require jQuery.
.fadeIn {
transition: opacity 1.25s;
}
Add the class fadeIn to your image elements, and now it'll fade.
To make it fade one after the other, use JavaScript timers to space out setting opacity to 1. Example:
var elements = [ /* Image elements to fade */ ];
for (var i = 0; i < elements.length; i++) {
setTimeout(function() {
elements[i].style.opacity = 1;
}, 1250 * i);
}
You can use callback function of fadeIn to load other image
function fadeIn() {
$("#imageOne").fadeIn("fast",function(){
$("#imageTwo").fadeIn("fast", function(){
$("#imageThr").fadeIn("fast");
});
});
}
This is what I came up with so far. Unfortunately, I haven't figure how to have them fade in, as the below just makes them appear one after the other. Though it's pure Javascript.
Any suggestions?
var imageOne = document.getElementById('imageOne');
var imageTwo = document.getElementById('imageTwo');
var imageThr = document.getElementById('imageThr');
function fadeIn(element) {
element.style.opacity += 0.9;
if (element.style.opacity < 1) {
setTimeout(function() {
fadeIn(element);
}, 100);
}
}
setTimeout(function() {
fadeIn(document.getElementById("imageOne"));
}, 1000);
setTimeout(function() {
fadeIn(document.getElementById("imageTwo"));
}, 5000);
setTimeout(function() {
fadeIn(document.getElementById("imageThr"));
}, 10000);