Acordeón suave con detalles elemento de divulgación

Tiempo de ejecución: 30 minutos. Empezar

Autor: Giana
Views Total: 256
Sitio oficial: Ir a la web
Actualizado: January 4, 2019
Licencia: MIT

Vista prévia

Acordeón suave con detalles elemento de divulgación

Descripción

Crear un acordeón suavemente plegable usando JavaScript, CSS3 animaciones, y detalles y Resumen Elements.

Funcionamiento

Codicode el acordeón.

<div class="container collapse">

<details>


<summary>Accordion 1</summary>


<div class="details-wrapper">



<div class="details-styling">








Details 1



</div>


</div>

</details>

<details>


<summary>Accordion 2</summary>


<div class="details-wrapper">



<div class="details-styling">








Details 2



</div>


</div>

</details>

<details>


<summary>Accordion 3</summary>


<div class="details-wrapper">



<div class="details-styling">








Details 3



</div>


</div>

</details>
</div>

El CSS necesario & estilos CSS3 para el acordeón.

/*

Please wrap your collapsible content in a single element or so help me

Must add a transition or it breaks because that's the whole purpose of this

Only one transition-duration works (see explanation on line #141 in JS)

You can add more to an inner wrapper (.details-styling)
*/
.collapse-init summary + * {

transition: all 0.25s ease-in-out;

overflow: hidden;
}

/*

Closed state. Any CSS transitions work here

The JS has a height calculation to make sliding opened/closed easier, but it's not necessary

Remove the height prop for a simple toggle on/off (after all that work I did for you?)
*/
.collapse-init :not(.panel-active) summary + * {

height: 0;

opacity: 0;

-webkit-transform: scale(0.9);





transform: scale(0.9);

-webkit-transform-origin: bottom center;





transform-origin: bottom center;
}

.collapse-init summary {

list-style: none;
}

.collapse-init summary::-webkit-details-marker {

display: none;
}

.collapse-init summary::before {

display: none;
}

.collapse-init summary {

cursor: pointer;
}

etails {

background: #fff;

border: 1px solid #d6d1e0;

border-bottom: 0;

list-style: none;
}

details:first-child {

border-radius: 6px 6px 0 0;
}

details:last-child {

border-bottom: 1px solid #d6d1e0;

border-radius: 0 0 6px 6px;
}

summary {

display: block;

transition: 0.2s;

font-weight: 700;

padding: 1em;
}

summary:focus {

outline: 2px solid #5b13ec;
}

.collapse-init summary::after {

border-right: 2px solid;

border-bottom: 2px solid;

content: '';

float: right;

width: 0.5em;

height: 0.5em;

margin-top: 0.25em;

-webkit-transform: rotate(45deg);





transform: rotate(45deg);

transition: inherit;
}

[open] summary {

background: #5b13ec;

color: #f8f5fe;
}

[open] summary::after {

margin-top: 0.5em;

-webkit-transform: rotate(225deg);





transform: rotate(225deg);
}

Cargue el detalles-Element-polyfill para el soporte de IE/Edge.

<script src="https://cdn.jsdelivr.net/gh/javan/[email protected]/dist/details-element-polyfill.js"></script>

El JavaScript principal para el acordeón.

var _createClass = function () {function defineProperties(target, props) {for (var i = 0; i < props.length; i++) {var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);}}return function (Constructor, protoProps, staticProps) {if (protoProps) defineProperties(Constructor.prototype, protoProps);if (staticProps) defineProperties(Constructor, staticProps);return Constructor;};}();function _classCallCheck(instance, Constructor) {if (!(instance instanceof Constructor)) {throw new TypeError("Cannot call a class as a function");}}miscPolyfillsForIE();

// main function
Collapse = function () {

function Collapse(container) {var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};_classCallCheck(this, Collapse);


var defaults = {



accordion: false,



initClass: 'collapse-init',



activeClass: 'panel-active',



heightClass: 'collapse-reading-height' };




this.settings = Object.assign({}, defaults, options);



this._container = container;


this._panels = container.querySelectorAll("details");



this.events = {



openingPanel: new CustomEvent('openingPanel'),



openedPanel: new CustomEvent('openedPanel'),



closingPanel: new CustomEvent('closingPanel'),



closedPanel: new CustomEvent('closedPanel') };


}


// Sets height of panel content

_createClass(Collapse, [{ key: '_setPanelHeight', value: function _setPanelHeight(panel) {



var contents = panel.querySelector("summary + *");




contents.style.height = contents.scrollHeight + "px";


}



// Removes height of panel content

}, { key: '_removePanelHeight', value: function _removePanelHeight(panel) {



var contents = panel.querySelector("summary + *");




contents.style.height = null;


}



//=== Open panel

}, { key: 'open', value: function open(panel) {



panel.dispatchEvent(this.events.openingPanel);




panel.open = true;


}



// Add height and active class, this triggers opening animation

}, { key: '_afterOpen', value: function _afterOpen(panel) {



this._setPanelHeight(panel);



panel.classList.add(this.settings.activeClass);


}



// Remove height on animation end since it's no longer needed

}, { key: '_endOpen', value: function _endOpen(panel) {



panel.dispatchEvent(this.events.openedPanel);




this._removePanelHeight(panel);


}



//=== Close panel, not toggling the actual [open] attr!

}, { key: 'close', value: function close(panel) {



panel.dispatchEvent(this.events.closingPanel);



this._afterClose(panel);


}



// Set height, wait a beat, then remove height to trigger closing animation

}, { key: '_afterClose', value: function _afterClose(panel) {var _this = this;



this._setPanelHeight(panel);




setTimeout(function () {




panel.classList.remove(_this.settings.activeClass);




_this._removePanelHeight(panel);



}, 100); //help, this is buggy and hacky


}



// Actually closes panel once animation finishes

}, { key: '_endClose', value: function _endClose(panel) {



panel.dispatchEvent(this.events.closedPanel);




panel.open = false;


}



//=== Toggles panel... just in case anyone needs this

}, { key: 'toggle', value: function toggle(panel) {



panel.open ? this.close(panel) : this.open(panel);


}



//=== Accordion closes all panels except the current passed panel

 }, { key: 'openSinglePanel', value: function openSinglePanel(panel) {var _this2 = this;



this._panels.forEach(function (element) {




if (panel == element && !panel.open) {





_this2.open(element);




} else {





_this2.close(element);




}



});


}



//=== Opens all panels just because

}, { key: 'openAll', value: function openAll() {var _this3 = this;



this._panels.forEach(function (element) {




_this3.open(element);



});


}



//=== Closes all panels just in case

}, { key: 'closeAll', value: function closeAll() {var _this4 = this;



this._panels.forEach(function (element) {




_this4.close(element);



});


}



// Now put it all together

}, { key: '_attachEvents', value: function _attachEvents() {var _this5 = this;



this._panels.forEach(function (panel) {




var toggler = panel.querySelector("summary");




var contents = panel.querySelector("summary + *");





// On panel open




panel.addEventListener("toggle", function (e) {





var isReadingHeight = panel.classList.contains(_this5.settings.heightClass);






if (panel.open && !isReadingHeight) {






_this5._afterOpen(panel);





}




});





toggler.addEventListener("click", function (e) {





// If accordion, stop default toggle behavior





if (_this5.settings.accordion) {






_this5.openSinglePanel(panel);






e.preventDefault();





}






// On attempting close, stop default close behavior to substitute our own





else if (panel.open) {







_this5.close(panel);







e.preventDefault();






}






// On open, proceed as normal (see toggle listener above)




});





/*







transitionend fires once for each animated property,







 but we want it to fire once for each click.







 So let's make sure to watch only a single property







Note this makes complex animations with multiple transition-durations impossible







Sorry






*/




var propToWatch = '';





// On panel finishing open/close animation




contents.addEventListener("transitionend", function (e) {





// Ignore transitions from child elements





if (e.target !== contents) {






return;





}






// Set property to watch on first fire





if (!propToWatch) propToWatch = e.propertyName;






// If watched property matches currently animating property





if (e.propertyName == propToWatch) {






var wasOpened = panel.classList.contains(_this5.settings.activeClass);






wasOpened ? _this5._endOpen(panel) : _this5._endClose(panel);





}




});



});


} }, { key: 'init', value: function init()



{



// Attach functionality



this._attachEvents();




// If accordion, open the first panel



if (this.settings.accordion) {




this.openSinglePanel(this._panels[0]);



}




// For styling purposes



this._container.classList.add(this.settings.initClass);




return this;


} }]);return Collapse;}();

// initialize the accordion
var makeMePretty = document.querySelector(".collapse");
var accordion = new Collapse(makeMePretty, { accordion: true }).init();

Te puede interesar: