JavaScript slidedown without jQuery

前端 未结 11 860
离开以前
离开以前 2020-11-27 14:03

I wish to have a similar effect to jQuery slidedown but without using jQuery or any other libary. I know it\'s \"possible\" as anything in jQuery can be don

相关标签:
11条回答
  • 2020-11-27 14:47

    Make it shorter:

    <button onclick="slide()"></button>
    
    <div id="box"></div>
    

    JS:

    slide(){document.getElementById("box").classList.toggle('hide');}
    
    #box {
      overflow: hidden;
      transition: all .5s ease-in-out;
      -webkit-transition: all 0.5s ease-in-out;
      -moz-transition: all 0.5s ease-in-out;
      -ms-transition: all 0.5s ease-in-out;
      -o-transition: all 0.5s ease-in-out;
    }
    .hide {
      height: 0px !important;
    }
    
    0 讨论(0)
  • 2020-11-27 14:48

    After tinkering a little with Symba's answer I came up with this to take into account padding and borders:

    toggleSlide = function (el) {
        var el_max_height = 0;
        if (el.getAttribute('data-max-height')) {
            if (el.style.maxHeight.replace('px', '').replace('%', '') === '0') {
                el.style.maxHeight = el.getAttribute('data-max-height');
                el.style.paddingTop = el.getAttribute('data-pad-top');
                el.style.paddingBottom = el.getAttribute('data-pad-bottom');
                el.style.borderTop = el.getAttribute('data-border-top');
                el.style.borderBottom = el.getAttribute('data-border-bottom');
            } else {
                el.style.maxHeight = '0';
                el.style.paddingTop = '0';
                el.style.paddingBottom = '0';
                el.style.borderBottom = '0';
                el.style.borderTop = '0';
            }
        } else {
            el_max_height = getHeight(el) + 'px';
            el.style['transition-property'] = 'max-height, padding-top, padding-bottom, border-bottom, border-top';
            el.style['transition-duration'] = '0.5s';
            el.style['transition-timing-function'] = 'ease-in-out';
            el.style.overflowY = 'hidden';
            el.style.maxHeight = '0';
            el.setAttribute('data-max-height', el_max_height);
            el.setAttribute('data-pad-top', el.style.paddingTop);
            el.setAttribute('data-pad-bottom', el.style.paddingBottom);
            el.setAttribute('data-border-top', el.style.borderTop);
            el.setAttribute('data-border-bottom', el.style.borderBottom);
            el.style.display = 'block';
            setTimeout(function () { el.style.maxHeight = el_max_height; }, 10);
        }
    }
    

    There's a bit of flicker at top border when expanding transition begins and I don't know (yet) how to fix that.

    I didn't modify Symba's getHeight function; for that see his answer.

    0 讨论(0)
  • 2020-11-27 14:50

    can be done in plain JavaScript. Just harder.

    Actually it's not too hard. You just need to get comfortable with setTimeout() (which is a good idea anyway since it teaches you the programming style of node.js). The most bare-bones implementation (does not have all of jQuery's features, that's left as homework for the reader):

    function slideDown (element, duration, finalheight, callback) {
        var s = element.style;
        s.height = '0px';
    
        var y = 0;
        var framerate = 10;
        var one_second = 1000;
        var interval = one_second*duration/framerate;
        var totalframes = one_second*duration/interval;
        var heightincrement = finalheight/totalframes;
        var tween = function () {
            y += heightincrement;
            s.height = y+'px';
            if (y<finalheight) {
                setTimeout(tween,interval);
            }
        }
        tween();
    }
    

    Of course, that's not the shortest possible way to write it and you don't have to declare all those variables like one_second etc. I just did it this way for clarity to show what's going on.

    This example is also shorter and easier to understand than trying to read jQuery's source code.


    Has anyone done something like this or any effects just using plain JavaScript?

    Oh yeah, sure, it's the sort of thing I do for fun on weekends:

    • http://slebetman.110mb.com/tank3.html (hint: units are clickable)
    • http://slebetman.110mb.com/jsgames/freakout
    0 讨论(0)
  • 2020-11-27 14:52

    The problem with the earlier answers is you need to know the height before you start. Many times you do not. I built a slid down the you first build a holder div, put the object to ge the slide down inside set the display of the object to block and get the height and use this for the sind. When the side is finished the holder is rmoved do the slide down when done remove it. below is the example.

    <!DOCTYPE html>
    <html>
        <head>
            <title></title>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        </head>
        <body>
            <div >
                <div id="test" style="height: 150px; width: 100px; background-color: yellowgreen; display:none">block</div>
            </div>
            <div>&nbsp;</div>
            <div onclick="slideUp(document.getElementById('test'));">slide Up</div>
            <div>&nbsp;</div>
            <div onclick="slideDown(document.getElementById('test'))">slide down</div>
            <script>
                function slideDown(obj, speed) {
                    var mySpeed = speed || 300;
                    var intervals = mySpeed / 30; // we are using 30 ms intervals
                    alert('intervals = ' + intervals);
                    var holder = document.createElement('div');//
                    var parent = obj.parentNode;
                    holder.setAttribute('style', 'height: 0px; overflow:hidden');
                    parent.insertBefore(holder, obj);
                    parent.removeChild(obj);
                    holder.appendChild(obj);
                    obj.style.display = obj.getAttribute("data-original-display") || "";
                    var height = obj.offsetHeight;
                    var sepHeight = height / intervals;
                    //  alert(sepHeight)
                    var timer = setInterval(function() {
                        var holderHeight = holder.offsetHeight;
                        if (holderHeight + sepHeight < height) {
                            holder.style.height = (holderHeight + sepHeight) + 'px';
                        } else {
                            // clean up
                            holder.removeChild(obj);
                            parent.insertBefore(obj, holder);
                            parent.removeChild(holder);
                            clearInterval(timer);
                        }
                    }, 30);
                }
    
                function slideUp(obj, speed) {
                    var mySpeed = speed || 300;
                    var intervals = mySpeed / 30; // we are using 30 ms intervals
                    var height = obj.offsetHeight;
                    var holder = document.createElement('div');//
                    var parent = obj.parentNode;
                    holder.setAttribute('style', 'height: ' + height + 'px; overflow:hidden');
                    parent.insertBefore(holder, obj);
                    parent.removeChild(obj);
                    holder.appendChild(obj);
                    var originalDisplay = (obj.style.display !== 'none') ? obj.style.display : '';
                    obj.setAttribute("data-original-display", originalDisplay);
                    var sepHeight = height / intervals;
                    //  alert(sepHeight)
                    var timer = setInterval(function() {
                        var holderHeight = holder.offsetHeight;
                        console.log(holderHeight);
                        if (holderHeight - sepHeight > 0) {
                            holder.style.height = (holderHeight - sepHeight) + 'px';
                        } else {
                            // clean up
                            obj.style.display = 'none';
                            holder.removeChild(obj);
                            parent.insertBefore(obj, holder);
                            parent.removeChild(holder);
                            clearInterval(timer);
                        }
                    }
                    , 30);
                }
    
            </script>
        </body>
    </html>
    
    0 讨论(0)
  • 2020-11-27 14:54

    I spent a lot of time to develop these functions and make them the most similar to JQuery's ones, I think they are some details to be optimized in the morph function mainly on length

    function morph( element, options, animationTime, callback ) { 
    // options is an array with the same structural of Properties and DiffValues and which contains the properties values we want the animation make
    	var ComputedElementStyle = window.getComputedStyle(element,null);
    	var AttrElementStyle = element.style;
    	var Properties = { // the actuals computed properties
    		width: 		parseInt( ComputedElementStyle.getPropertyValue("width")),
    		height: 	parseInt( ComputedElementStyle.getPropertyValue("height")),
    		padding: {
    			top: 	parseInt(ComputedElementStyle.getPropertyValue("padding-top")),
    			right: 	parseInt(ComputedElementStyle.getPropertyValue("padding-right")),
    			bot: 	parseInt(ComputedElementStyle.getPropertyValue("padding-bottom")),
    			left:	parseInt(ComputedElementStyle.getPropertyValue("padding-left"))
    			},
    		margin:{
    			top: 	parseInt(ComputedElementStyle.getPropertyValue("margin-top")),
    			right: 	parseInt(ComputedElementStyle.getPropertyValue("margin-right")),
    			bot: 	parseInt(ComputedElementStyle.getPropertyValue("margin-bottom")),
    			left:	parseInt(ComputedElementStyle.getPropertyValue("margin-left"))
    			} 
    	};
    	var DiffValues = { // the differences between actual properties values and values we want to
    		width:		(options['width']!=null) ? (options['width'] - Properties['width']) : 0,
    		height:		(options['height']!=null) ? (options['height'] - Properties['height']) : 0,
    		padding: {
    			top: 	(options['padding']&&options['padding']['top']!=null) ? options['padding']['top'] - Properties['padding']['top'] : 0,
    			right: 	(options['padding']&&options['padding']['right']!=null) ? options['padding']['right'] - Properties['padding']['right'] : 0,
    			bot: 	(options['padding']&&options['padding']['bot']!=null) ? options['padding']['bot'] - Properties['padding']['bot'] : 0,
    			left: 	(options['padding']&&options['padding']['left']!=null) ? options['padding']['left'] - Properties['padding']['left'] : 0
    			},
    		margin:{
    			top: 	(options['margin']&&options['margin']['top']!=null) ? options['margin']['top'] - Properties['margin']['top'] : 0,
    			right: 	(options['margin']&&options['margin']['right']!=null) ? options['margin']['right'] - Properties['margin']['right'] : 0,
    			bot: 	(options['margin']&&options['margin']['bot']!=null) ? options['margin']['bot'] - Properties['margin']['bot'] : 0,
    			left: 	(options['margin']&&options['margin']['left']!=null) ? options['margin']['left'] - Properties['margin']['left'] : 0
    			}
    	};
    	var beginTime = new Date().getTime(); // time at begining of animation
    	animationTime = (animationTime!=null) ? animationTime : 250;
    	AttrElementStyle.overflow = "hidden"; // disable the potentials scrollbars
    	
    	var sinceBeginTime; // time since the begining
    	var progressFactor; // coeficient that correspond to the advancement of the animation
    	
    	timer = setInterval(function() { // begin of the animation
    		sinceBeginTime = new Date().getTime() - beginTime;
    		if( sinceBeginTime < animationTime ) {
    			progressFactor = sinceBeginTime / animationTime;
    			AttrElementStyle.width=(Properties['width'] + DiffValues['width'] * progressFactor)		+"px";
    			AttrElementStyle.height=(Properties['height'] + DiffValues['height'] * progressFactor)	+"px";
    			AttrElementStyle.padding=
    				(Properties['padding']['top'] + DiffValues['padding']['top'] * progressFactor)		+"px "+
    				(Properties['padding']['right'] + DiffValues['padding']['right'] * progressFactor)	+"px "+
    				(Properties['padding']['bot'] + DiffValues['padding']['bot'] * progressFactor)		+"px "+
    				(Properties['padding']['left'] + DiffValues['padding']['left'] * progressFactor)	+"px";
    			AttrElementStyle.margin=
    				(Properties['margin']['top'] + DiffValues['margin']['top'] * progressFactor)		+"px "+
    				(Properties['margin']['right'] + DiffValues['margin']['right'] * progressFactor)	+"px "+
    				(Properties['margin']['bot'] + DiffValues['margin']['bot'] * progressFactor)		+"px "+
    				(Properties['margin']['left'] + DiffValues['margin']['left'] * progressFactor)		+"px";
    		}else {
    			AttrElementStyle.width=options['width']		+"px";
    			AttrElementStyle.height=options['height']	+"px";
    			AttrElementStyle.padding=
    				(Properties['padding']['top'] + DiffValues['padding']['top'])		+"px "+
    				(Properties['padding']['right'] + DiffValues['padding']['right'])	+"px "+
    				(Properties['padding']['bot'] + DiffValues['padding']['bot'])		+"px "+
    				(Properties['padding']['left'] + DiffValues['padding']['left'])		+"px";
    			AttrElementStyle.margin=
    				(Properties['margin']['top'] + DiffValues['margin']['top'])			+"px "+
    				(Properties['margin']['right'] + DiffValues['margin']['right'])		+"px "+
    				(Properties['margin']['bot'] + DiffValues['margin']['bot'])			+"px "+
    				(Properties['margin']['left'] + DiffValues['margin']['left'])		+"px";
    			clearInterval( timer ); // end of the animation
    			if( callback!=null ) // if there is a CALLBACK then call it
    				callback(Properties);
    		}
    	},15);
    }
    function slideUp( element, animationTime , callback) {
    	morph( element, {
    			height:0,
    			padding:{
    				top:0,
    				bot:0
    			},
    			margin:{
    				top:0,
    				bot:0
    			} },  animationTime, function(Properties) {
    			// at the end of the slideUp we display: none the element and clean the other properties from style attribute
    			var AttrElementStyle = element.style;
    			AttrElementStyle.width="";
    			AttrElementStyle.height="";
    			AttrElementStyle.padding="";
    			AttrElementStyle.margin="";
    			element.style.display = 'none';
    			if(callback)
    				callback();
    	});
    }
    
    function slideDown( element, animationTime , callback) {
    	var AttrElementStyle = element.style;
    	var ComputedElementStyle = window.getComputedStyle(element,null);
    	
    	AttrElementStyle.display="block";
    	
    	var options = { // the computed properties when element is displayed
    	width: 		parseInt( ComputedElementStyle.getPropertyValue("width")),
    	height: 	parseInt( ComputedElementStyle.getPropertyValue("height")),
    	padding: {
    		top: 	parseInt(ComputedElementStyle.getPropertyValue("padding-top")),
    		bot: 	parseInt(ComputedElementStyle.getPropertyValue("padding-bottom"))
    		},
    	margin:{
    		top: 	parseInt(ComputedElementStyle.getPropertyValue("margin-top")),
    		bot: 	parseInt(ComputedElementStyle.getPropertyValue("margin-bottom"))
    		} 
    	};
    	// after getting the actuals properties values of the element we flatten it
    	AttrElementStyle.height="0";
    	AttrElementStyle.paddingTop="0";
    	AttrElementStyle.paddingBottom="0";
    	AttrElementStyle.marginTop="0";
    	AttrElementStyle.marginBottom="0";
    	
    	morph( element, options , animationTime, function() { // morph the element from flat to the options properties that are right
    		// at the end of slideDown we clean up the style but keep the display: block if the element is display: none in the stylesheet
    		AttrElementStyle.width="";
    		AttrElementStyle.height="";
    		AttrElementStyle.padding="";
    		AttrElementStyle.margin="";
    		element.style.display = 'block';
    		if(callback) // if there is a CALLBACK then call it (we are in the morph() callback)
    			callback();
    	})
    }
    p{
      width:50%;
      height:auto;
      padding:40px 0 10px;
      margin: 10px 0 40px;
      border:2px solid red
    }
    div{
      border:1px solid blue;
      padding:10px
    }
    <div>
      <p id='p'>loiloilozoifboiygdouhbodihfgsd</br>rihgdggisbifghbsoifnsf</br>giodsbgsigfbsjgsgs</p>
    </div>
    
    <button onClick="slideUp( document.getElementById('p') ,500)">testUp</button>
    <button onClick="slideDown( document.getElementById('p') ,500)">testDown</button>
    
    <button id='btn1' onClick="morph( document.getElementById('btn1'),{ width: 120,height:130,padding:{top:70,left:50},margin:{right:40}} ,1000)">morphIt</button>
    <button onClick="document.getElementById('btn1').style=''">reset btn1</button>

    0 讨论(0)
提交回复
热议问题