animated 'show' without jQuery
I want to do a little animation on this latest website ii'm working 开发者_运维技巧on. Basically, I need one or two divs/paragraph show/hide based on onClick event on either radio buttons set or checkbox (then, if radio/check is value A, show div/p, if it's B then hide it)
The thing is, that this is all I would like to javascript-ify on that particular website, so jQuery looks like a little overkill (even the minified version)
Is there any simple [I can't stress this enough] way to do this either by vanilla javascript or some other minimal library [I'm generally looking for something <2kB for events and little animation (height)]
Any ideas?
Thank you!
Edit: Thanks to everyone, I just realized, that although some of the things I need to could be done via smart html+js, the rules of showing/hiding the right divs are so complicated, that it's worth of 30kB of including jQuery (even more if it's already cached from CDN), so I'll stick with jQuery. Cheers to everyone :)
edit: JS+CSS3 transition followup It works :) http://jsfiddle.net/ygZM7/23/
The only thing is: if height was previously not set (dynamic), first time you set it, the background flicks (goes from 0px height).
I've came up with my own quick script.. here goes nothing:
var AnimationStep = 10; //pixels
var AnimationInterval = 100; //milliseconds
window.onload = function() {
var oDiv = document.getElementById("Div1");
oDiv.style.display = "block";
var height = oDiv.clientHeight;
oDiv.style.height = "0px";
Animate(oDiv, height);
};
function Animate(element, targetHeight) {
var curHeight = element.clientHeight;
if (curHeight >= targetHeight)
return true;
element.style.height = (curHeight + AnimationStep) + "px";
window.setTimeout(function() {
Animate(element, targetHeight);
}, AnimationInterval);
return false;
}
This will "animate" element with id Div1
and you can control the speed by playing with the two numbers on top: bigger Step means bigger chunk is displayed every time and smaller Interval means faster animation.
This code requires the following style to be applied on the element:
#Div1 { display: none; overflow: hidden; }
And of course live test case: http://jsfiddle.net/yahavbr/BbWCp/
It should be pretty simple to animate the width as well (maybe even in the same time) to achieve "cooler" effect. :)
If you want to do the animation by updating the "height" of the element, thus making it sort-of a "slide down" (or "up" I guess) effect, it shouldn't be too hard. You just have to make small changes quickly with a timer.
<div id='animateMe' style='height: 0px; overflow: hidden'>
blah blah blah
</div>
<script>
(function() {
var div = document.getElementById('animateMe');
var curh = 0, finalh = 100;
var interval = setInterval(function() {
if (curh === finalh) {
clearInterval(interval);
return;
}
curh = curh + 1;
div.style.height = curh + 'px';
}, 50);
})();
</script>
That's just a sample; you could wire the code up to an event handler or whatever.
You could use CSS transitions. doesn't work in every browser but that's totally acceptable that users in IE7 don't have the exact same experience as users in Chrome/Safari/FF4.
<script>
function swap(rad) {
var p1 = document.getElementById("p1");
var p2 = document.getElementById("p2");
if (rad.value === "1") {
p1.style.display = "none";
p2.style.display = "block";
} else {
p1.style.display = "block";
p2.style.display = "none";
}
return false;
}
</script>
<label><input type="radio" name="r" value="1" onclick="swap(this)" />One</label>
<label><input type="radio" name="r" value="2" onclick="swap(this)" />Two</label>
<p id="p1">Hi there</p>
<p id="p2">Hey there</p>
For what it's worth, I had the same question, but wanted to have the height of the element even if it is not set in the style, and even if the element has display: none. So my solution is to steal the element, make it invisible, place it somewhere unseen, make its display: block, measure its height using clientHeight, put it back into its original place with original settings and then do the sliding. Here it is:
function slideElementIn(myid) {
mydiv= document.getElementById(myid);
if(mydiv.style.display!="none")return;
// clientHeight is zero when display is none. So, prepare:
inipos = mydiv.style.position;
inivisibility = mydiv.style.visibility;
iniz = mydiv.style.zIndex;
initop = mydiv.style.top;
inileft = mydiv.style.left;
inioverflow = mydiv.style.overflow;
mydiv.style.zIndex = "-999";
mydiv.style.top = "0";
mydiv.style.left = "0";
mydiv.style.visibility = "hidden";
mydiv.style.position = "fixed";
mydiv.style.display = "block";
finHeight = mydiv.clientHeight; // got it!
// repair damage:
mydiv.style.display = "none";
mydiv.style.position = inipos;
mydiv.style.visibility = inivisibility;
mydiv.style.zIndex = iniz;
mydiv.style.top = initop;
mydiv.style.left = inileft;
iniHeight = mydiv.style.height;
mydiv.style.height = 0;
mydiv.style.display = "block";
mydiv.style.overflow="hidden";
var i = 1; // set your counter to 1
function myLoop2 (i,mydiv,finHeight,iniHeight,inioverflow) { // create a loop function
setTimeout(function () { // call a 3s setTimeout when the loop is called
mydiv.style.height = finHeight * easeIn(i * (1./fadeDuration));
i++; // increment the counter
if (i < fadeDuration) { // if the counter < 10, call the loop function
myLoop2(i,mydiv,finHeight,iniHeight,inioverflow); // .. again which will trigger another
} else {
mydiv.style.height = iniHeight;
mydiv.style.overflow=inioverflow;
} // .. setTimeout()
}, 1)
}
myLoop2(i,mydiv,finHeight,iniHeight,inioverflow);
}
function slideElementOut(myid) {
mydiv= document.getElementById(myid);
itsdisplay = mydiv.style.display ;
if ( itsdisplay != "none" ) {
finHeight = mydiv.clientHeight;
iniHeight = mydiv.style.height;
inioverflow = mydiv.style.overflow;
mydiv.style.overflow = "hidden";
var i = fadeDuration; // set your counter to 1
function myLoop (i,mydiv,finHeight,iniHeight,inioverflow) { // create a loop function
setTimeout(function () { // call a 3s setTimeout when the loop is called
mydiv.style.height = finHeight * easeOut(i * (1./fadeDuration));
i--; // increment the counter
if (i > 0) { // if the counter < 10, call the loop function
myLoop(i,mydiv,finHeight,iniHeight,inioverflow); // .. again which will trigger another
} else {
mydiv.style.display = "none";
mydiv.style.height = iniHeight;
mydiv.style.overflow=inioverflow;
} // .. setTimeout()
}, 1)
}
myLoop(i,mydiv,finHeight,iniHeight,inioverflow);
}
}
I figure it's still worth posting this here, because when I searched for my answer, I got to this question, but needed just a few steps more. I hope this is of help to someone.
I recently converted a website to remove its dependencies on jQuery and it used fadeIn()
and hide()
for an animated "tab page"-like UI - where if the user clicked on another tab then the current tab page would instantly disappear while the new tab quickly fades in.
I wanted to avoid doing any animation myself in Javascript, especially as CSS3's transition
and animation
features are now well-supported. As this question is originally from 2011, I assumed it could do with an update, here's what I used: no jQuery and no manual animations (setInterval
, setTimeout
, requestAnimationFrame
, etc):
From this:
<div id="tabContainer">
<ul>
<li class="tab" data-tab="tabPage1">Page 1</li>
<li class="tab" data-tab="tabPage2">Page 2</li>
<li class="tab" data-tab="tabPage3">Page 3</li>
</ul>
<div class="tabPage" id="tabPage1"></div>
<div class="tabPage" id="tabPage2"></div>
<div class="tabPage" id="tabPage3"></div>
</div>
$('#tabContainer .tab').click(function(e) {
// when a tab is clicked:
// 1. Hide all other tabs
$('#tabContainer .tabPage').hide();
// 2. Show the selected tab, determined from the clicked element's `data-tab` attribute:
$( '#' + $(this).data('tab') ).fadeIn();
});
(and an 85KB jQuery.min.js download...)
to just this:
var nodes = document.querySelectorAll('#tabContainer .tab');
for(var i=0; i < nodes.length; i++) {
nodes[i].addEventListener('click', function(event) {
var tabPages = document.querySelectorAll('#tabContainer .tabPage');
for(var j=0; j < tabPages.length; j++) {
tabPages[i].style.display = 'none';
tabPages[i].classList.remove('animFadeIn');
}
var tabToShow = document.querySelector('#' + event.currentTarget.dataset['tab']);
tabToShow.style.display = '';
tabToShow.classList.add('animFadeIn');
});
}
And this CSS:
.animFadeIn {
animation: animFadeInAnim 300ms;
}
@keyframes animFadeInAnim {
0% {
display: block;
opacity: 0;
}
100% {
opacity: 1.0;
}
}
You cannot use CSS transition
s because an opacity
transition is blocked whenever the display:
property is changed, but CSS animations do support it.
This can be made shorter by replacing the for(var...
loops with for(var e of...
, however this kind of loop does not have wide browser support yet (as of June 2016).
Use the following transition function:
function transition(style, prop, unit, from, to, duration, callback){
var change = from-to,
now = performance.now(),
end = now + duration;
function anim8(){
now = end - performance.now();
if (now < 0){
style[prop] = to + unit;
return callback();
}
style[prop] = to + change*now/duration + unit;
requestAnimationFrame(anim8);
}
anim8();
}
Example:
transition(
document.body.style,
'width',
'vw', // unit (appended onto the end)
95, // start value
50, // end value
5000, // duration (miliseconds)
function(){console.log('done!')} // function to run after finished
);
function transition(style, prop, unit, from, to, duration, callback) {
var change = from - to,
now = performance.now(),
end = now + duration;
function anim8() {
now = end - performance.now();
if (now < 0) {
style[prop] = to + unit;
return callback();
}
style[prop] = to + change * now / duration + unit;
requestAnimationFrame(anim8);
}
anim8();
}
<body style="border:1px solid">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus at consequat nisl. Vestibulum tempor dapibus venenatis. Donec sed auctor elit. Suspendisse eget lectus nulla. Pellentesque dapibus tempus tortor, eu cursus ligula iaculis ut. Donec a ipsum elit. Suspendisse gravida fringilla dolor, pulvinar scelerisque ante consectetur vitae.
I sometimes find myself using this handy function as opposed to CSS transtions because, lets be honest: CSS transitions were not entirely thought-through. I am not saying that CSS transitions are bad (I sometimes use them), all I am saying is it's hard to use them everywhere. It can often be quite difficult to synchronize voiding the offsetWidth to force a reflow only to end up with a glitchy transition so you then try to setTimeout offset things until it gets unbearably complicated, but still glitchy. For what you use transitions for, you might not have this problem, but for what I use them for, I do have this problem. What they should have included in the spec was an Element.reflow()
function that will go a step further than just void Element.offsetWidth
, and actually attempt to synchronize and 'sort-out' the transitions. That single function would have made my job as a dev 10000000000000000000000% easier.
the following is a fadeIn fadeOut animation script.You can use it directly. Works like a charm in any browser.
var TimeToFade = 1000.0;
function fade(eid)
{
var element = document.getElementById(eid);
if(element == null)
return;
if(element.FadeState == null)
{
if(element.style.opacity == null
|| element.style.opacity == ''
|| element.style.opacity == '1')
{
element.FadeState = 2;
}
else
{
element.FadeState = -2;
}
}
if(element.FadeState == 1 || element.FadeState == -1)
{
element.FadeState = element.FadeState == 1 ? -1 : 1;
element.FadeTimeLeft = TimeToFade - element.FadeTimeLeft;
}
else
{
element.FadeState = element.FadeState == 2 ? -1 : 1;
element.FadeTimeLeft = TimeToFade;
setTimeout("animateFade(" + new Date().getTime() + ",'" + eid + "')", 33);
}
精彩评论