简单伸缩面板制作(来源于CSS彻底设计与研究)

本文介绍了如何使用CSS和JavaScript创建一个基本的伸缩面板(Accordion)效果。通过阅读,你可以学习到如何利用HTML结构、CSS样式以及JavaScript交互来实现这一常见的网页组件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

accordion.html

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>自动伸缩面板</title>
        <link href="pages/accord1/accordion.css" type="text/css" rel="stylesheet">
        <script src="pages/accord1/accordion.js" type="text/javascript"></script>
    </head>
    <body>
        <div id="Accordion1" class="Accordion" tabindex="0">
            <div class="AccordionPanel">
                <div class="AccordionPanelTab top">Home</div>
                <div class="AccordionPanelContent"><img src="cup.gif">
                    <p>An anchor tag can be used inside of a Collapsible Panel Tab so that the
                        key board focus ring appears *inside* the tab instead of around the tab.
                        This is an example of how to make the text within the anchor tag look
                        like non-anchor (normal) text.This is an example of how to change the appearance of the panel tab that is
                        currently open. The class "CollapsiblePanelOpen" is programatically added and removed
                        from panel.</p>
                </div>
            </div>
            <div class="AccordionPanel">
                <div class="AccordionPanelTab">Web Design</div>
                <div class="AccordionPanelContent">An anchor tag can be used inside of a Collapsible Panel Tab so that the key board focus ring appears *inside* the tab instead of around the tab. This is an example of how to make the text within the anchor tag look like non-anchor (normal) text.This is an example of how to change the appearance of the panel tab that is currently open. The class "CollapsiblePanelOpen" is programatically added and removed from panels as the user clicks on the tabs within the CollapsiblePanel. on the tabs within the CollapsiblePanel
                </div>
            </div>
            <div class="AccordionPanel">
                <div class="AccordionPanelTab">Web Dev</div>
                <div class="AccordionPanelContent">An anchor tag can be used inside of a Collapsible Panel Tab so that the key board focus ring appears *inside* the tab instead of around the tab. This is an example of how to make the text within the anchor tag look like non-anchor (normal) text.This is an example of how to change the appearance of the panel tab that is currently open. The class "CollapsiblePanelOpen" is programatically added and removed from panels as the user clicks on the tabs within the CollapsiblePanel. on the tabs within the CollapsiblePanel
                </div>
            </div>
            <div class="AccordionPanel">
                <div class="AccordionPanelTab">Map</div>
                <div class="AccordionPanelContent">An anchor tag can be used inside of a Collapsible Panel Tab so that the key board focus ring appears *inside* the tab instead of around the tab. This is an example of how to make the text within the anchor tag look like non-anchor (normal) text.This is an example of how to change the appearance of the panel tab that is currently open. The class "CollapsiblePanelOpen" is programatically added and removed from panels as the user clicks on the tabs within the CollapsiblePanel. on the tabs within the CollapsiblePanel
                </div>
            </div>
        </div>
        <script type="text/javascript">
            var Accordion1 = new Spry.Widget.Accordion("Accordion1");
        </script>
    </body>
</html>

accordion.css

@charset "UTF-8";

.Accordion {
    width:300px;
    overflow: hidden;
    border-bottom:2px #006 solid;
}
.AccordionPanel {
    margin: 0px;
    padding: 0px;
}
.AccordionPanelTab {
    background: url(ac-open-back.gif) no-repeat;
    font: bold 16px Arial;
    color:#006;
    line-height:30px;
    height:30px;
    margin: 0px;
    padding: 0px 30px;
    cursor: pointer;
    -moz-user-select: none;
    -khtml-user-select: none;
}
.top{
    background: url(ac-open-back-top.gif) no-repeat;
}
.AccordionPanelContent {
    background:#ADF;
    font:12px/18px Arial;
    overflow: auto;
    margin: 0px;
    padding: 0 10px;
    height: 230px;
    border-left:2px #006 solid;
    border-right:2px #006 solid;
}
.AccordionPanelContent img{
    float:left;
    padding:2px;
    margin:2px;
    border:1px #aaa dashed;
}
.AccordionPanelOpen .AccordionPanelTab {
    background: url(ac-open-back-open.gif) no-repeat;
}
.AccordionPanelOpen .top {
    background: url(ac-open-back-top-open.gif) no-repeat;
}

accordion.js

var Spry;
if (!Spry) Spry = {};
if (!Spry.Widget) Spry.Widget = {};

Spry.Widget.Accordion = function(element, opts)
{
    this.element = this.getElement(element);
    this.defaultPanel = 0;
    this.hoverClass = "AccordionPanelTabHover";
    this.openClass = "AccordionPanelOpen";
    this.closedClass = "AccordionPanelClosed";
    this.focusedClass = "AccordionFocused";
    this.enableAnimation = true;
    this.enableKeyboardNavigation = true;
    this.currentPanel = null;
    this.animator = null;
    this.hasFocus = null;
    this.duration = 100;

    this.previousPanelKeyCode = Spry.Widget.Accordion.KEY_UP;
    this.nextPanelKeyCode = Spry.Widget.Accordion.KEY_DOWN;

    this.useFixedPanelHeights = true;
    this.fixedPanelHeight = 0;

    Spry.Widget.Accordion.setOptions(this, opts, true);


    if (Spry.Widget.Accordion.onloadDidFire)
        this.attachBehaviors();
    else
        Spry.Widget.Accordion.loadQueue.push(this);
};

Spry.Widget.Accordion.onloadDidFire = false;
Spry.Widget.Accordion.loadQueue = [];

Spry.Widget.Accordion.addLoadListener = function(handler)
{
    if (typeof window.addEventListener != 'undefined')
        window.addEventListener('load', handler, false);
    else if (typeof document.addEventListener != 'undefined')
        document.addEventListener('load', handler, false);
    else if (typeof window.attachEvent != 'undefined')
        window.attachEvent('onload', handler);
};

Spry.Widget.Accordion.processLoadQueue = function(handler)
{
    Spry.Widget.Accordion.onloadDidFire = true;
    var q = Spry.Widget.Accordion.loadQueue;
    var qlen = q.length;
    for (var i = 0; i < qlen; i++)
        q[i].attachBehaviors();
};

Spry.Widget.Accordion.addLoadListener(Spry.Widget.Accordion.processLoadQueue);

Spry.Widget.Accordion.prototype.getElement = function(ele)
{
    if (ele && typeof ele == "string")
        return document.getElementById(ele);
    return ele;
};

Spry.Widget.Accordion.prototype.addClassName = function(ele, className)
{
    if (!ele || !className || (ele.className && ele.className.search(new RegExp("\\b" + className + "\\b")) != -1))
        return;
    ele.className += (ele.className ? " " : "") + className;
};

Spry.Widget.Accordion.prototype.removeClassName = function(ele, className)
{
    if (!ele || !className || (ele.className && ele.className.search(new RegExp("\\b" + className + "\\b")) == -1))
        return;
    ele.className = ele.className.replace(new RegExp("\\s*\\b" + className + "\\b", "g"), "");
};

Spry.Widget.Accordion.setOptions = function(obj, optionsObj, ignoreUndefinedProps)
{
    if (!optionsObj)
        return;
    for (var optionName in optionsObj)
    {
        if (ignoreUndefinedProps && optionsObj[optionName] == undefined)
            continue;
        obj[optionName] = optionsObj[optionName];
    }
};

Spry.Widget.Accordion.prototype.onPanelTabMouseOver = function(panel)
{
    if (panel)
        this.addClassName(this.getPanelTab(panel), this.hoverClass);
};

Spry.Widget.Accordion.prototype.onPanelTabMouseOut = function(panel)
{
    if (panel)
        this.removeClassName(this.getPanelTab(panel), this.hoverClass);
};

Spry.Widget.Accordion.prototype.openPanel = function(panel)
{
    var panelA = this.currentPanel;
    var panelB = panel;
	
    if (!panelB || panelA == panelB)	
        return;

    var contentA; 
    if( panelA )
        contentA = this.getPanelContent(panelA);
    var contentB = this.getPanelContent(panelB);

    if (! contentB)
        return;

    if (this.useFixedPanelHeights && !this.fixedPanelHeight)
    {
        this.fixedPanelHeight = (contentA.offsetHeight) ? contentA.offsetHeight : contentA.scrollHeight;
    }

    if (this.enableAnimation)
    {
        if (this.animator)
            this.animator.stop();
        this.animator = new Spry.Widget.Accordion.PanelAnimator(this, panelB, {
            duration: this.duration
        });
        this.animator.start();
    }
    else
    {
        if(contentA)
            contentA.style.height = "0px";
        contentB.style.height = (this.useFixedPanelHeights ? this.fixedPanelHeight : contentB.scrollHeight) + "px";
    }

    if(panelA)
    {
        this.removeClassName(panelA, this.openClass);
        this.addClassName(panelA, this.closedClass);
    }

    this.removeClassName(panelB, this.closedClass);
    this.addClassName(panelB, this.openClass);

    this.currentPanel = panelB;
};

Spry.Widget.Accordion.prototype.openNextPanel = function()
{
    var panels = this.getPanels();
    var curPanelIndex = this.getCurrentPanelIndex();
	
    if( panels && curPanelIndex >= 0 && (curPanelIndex+1) < panels.length )
        this.openPanel(panels[curPanelIndex+1]);
};

Spry.Widget.Accordion.prototype.openPreviousPanel = function()
{
    var panels = this.getPanels();
    var curPanelIndex = this.getCurrentPanelIndex();
	
    if( panels && curPanelIndex > 0 && curPanelIndex < panels.length )
        this.openPanel(panels[curPanelIndex-1]);
};

Spry.Widget.Accordion.prototype.openFirstPanel = function()
{
    var panels = this.getPanels();
    if( panels )
        this.openPanel(panels[0]);
};

Spry.Widget.Accordion.prototype.openLastPanel = function()
{
    var panels = this.getPanels();
    if( panels )
        this.openPanel(panels[panels.length-1]);
};

Spry.Widget.Accordion.prototype.onPanelClick = function(panel)
{
    // if (this.enableKeyboardNavigation)
    // 	this.element.focus();
    if (panel != this.currentPanel)
        this.openPanel(panel);
    this.focus();
};

Spry.Widget.Accordion.prototype.onFocus = function(e)
{
    // this.element.focus();
    this.hasFocus = true;
    this.addClassName(this.element, this.focusedClass);
};

Spry.Widget.Accordion.prototype.onBlur = function(e)
{
    // this.element.blur();
    this.hasFocus = false;
    this.removeClassName(this.element, this.focusedClass);
};

Spry.Widget.Accordion.KEY_UP = 38;
Spry.Widget.Accordion.KEY_DOWN = 40;

Spry.Widget.Accordion.prototype.onKeyDown = function(e)
{
    var key = e.keyCode;
    if (!this.hasFocus || (key != this.previousPanelKeyCode && key != this.nextPanelKeyCode))
        return true;
	
    var panels = this.getPanels();
    if (!panels || panels.length < 1)
        return false;
    var currentPanel = this.currentPanel ? this.currentPanel : panels[0];
    var nextPanel = (key == this.nextPanelKeyCode) ? currentPanel.nextSibling : currentPanel.previousSibling;
	
    while (nextPanel)
    {
        if (nextPanel.nodeType == 1 /* Node.ELEMENT_NODE */)
            break;
        nextPanel = (key == this.nextPanelKeyCode) ? nextPanel.nextSibling : nextPanel.previousSibling;
    }
	
    if (nextPanel && currentPanel != nextPanel)
        this.openPanel(nextPanel);

    if (e.stopPropagation)
        e.stopPropagation();
    if (e.preventDefault)
        e.preventDefault();

    return false;
};

Spry.Widget.Accordion.prototype.attachPanelHandlers = function(panel)
{
    if (!panel)
        return;

    var tab = this.getPanelTab(panel);

    if (tab)
    {
        var self = this;
        Spry.Widget.Accordion.addEventListener(tab, "click", function(e) {
            return self.onPanelClick(panel);
        }, false);
        Spry.Widget.Accordion.addEventListener(tab, "mouseover", function(e) {
            return self.onPanelTabMouseOver(panel);
        }, false);
        Spry.Widget.Accordion.addEventListener(tab, "mouseout", function(e) {
            return self.onPanelTabMouseOut(panel);
        }, false);
    }
};

Spry.Widget.Accordion.addEventListener = function(element, eventType, handler, capture)
{
    try
    {
        if (element.addEventListener)
            element.addEventListener(eventType, handler, capture);
        else if (element.attachEvent)
            element.attachEvent("on" + eventType, handler);
    }
    catch (e) {}
};

Spry.Widget.Accordion.prototype.initPanel = function(panel, isDefault)
{
    var content = this.getPanelContent(panel);
    if (isDefault)
    {
        this.currentPanel = panel;
        this.removeClassName(panel, this.closedClass);
        this.addClassName(panel, this.openClass);
    }
    else
    {
        this.removeClassName(panel, this.openClass);
        this.addClassName(panel, this.closedClass);
        content.style.height = "0px";
    }
	
    this.attachPanelHandlers(panel);
};

Spry.Widget.Accordion.prototype.attachBehaviors = function()
{
    var panels = this.getPanels();
    for (var i = 0; i < panels.length; i++)
    {
        this.initPanel(panels[i], i == this.defaultPanel);
    }

    if (this.enableKeyboardNavigation)
    {
        // XXX: IE doesn't allow the setting of tabindex dynamically. This means we can't
        // rely on adding the tabindex attribute if it is missing to enable keyboard navigation
        // by default.

        var tabIndexAttr = this.element.attributes.getNamedItem("tabindex");
        // if (!tabIndexAttr) this.element.tabindex = 0;
        if (tabIndexAttr)
        {
            var self = this;
            Spry.Widget.Accordion.addEventListener(this.element, "focus", function(e) {
                return self.onFocus(e);
            }, false);
            Spry.Widget.Accordion.addEventListener(this.element, "blur", function(e) {
                return self.onBlur(e);
            }, false);
            Spry.Widget.Accordion.addEventListener(this.element, "keydown", function(e) {
                return self.onKeyDown(e);
            }, false);
        }
    }
};

Spry.Widget.Accordion.prototype.getPanels = function()
{
    return this.getElementChildren(this.element);
};

Spry.Widget.Accordion.prototype.getCurrentPanel = function()
{
    return this.currentPanel;
};

Spry.Widget.Accordion.prototype.getCurrentPanelIndex = function()
{
    var panels = this.getPanels();
    for( var i = 0 ; i < panels.length; i++ )
    {
        if( this.currentPanel == panels[i] )
            return i;
    }
    return 0;
};

Spry.Widget.Accordion.prototype.getPanelTab = function(panel)
{
    if (!panel)
        return null;
    return this.getElementChildren(panel)[0];
};

Spry.Widget.Accordion.prototype.getPanelContent = function(panel)
{
    if (!panel)
        return null;
    return this.getElementChildren(panel)[1];
};

Spry.Widget.Accordion.prototype.getElementChildren = function(element)
{
    var children = [];
    var child = element.firstChild;
    while (child)
    {
        if (child.nodeType == 1 /* Node.ELEMENT_NODE */)
            children.push(child);
        child = child.nextSibling;
    }
    return children;
};

Spry.Widget.Accordion.prototype.focus = function()
{
    if (this.element && this.element.focus)
        this.element.focus();
};

/////////////////////////////////////////////////////

Spry.Widget.Accordion.PanelAnimator = function(accordion, panel, opts)
{
    this.timer = null;
    this.interval = 0;
    this.stepCount = 0;

    this.fps = 0;
    this.steps = 10;
    this.duration = 500;
    this.onComplete = null;

    this.panel = panel;
    this.panelToOpen = accordion.getElement(panel);
    this.panelData = [];

    Spry.Widget.Accordion.setOptions(this, opts, true);


    // If caller specified speed in terms of frames per second,
    // convert them into steps.

    if (this.fps > 0)
    {
        this.interval = Math.floor(1000 / this.fps);
        this.steps = parseInt((this.duration + (this.interval - 1)) / this.interval);
    }
    else if (this.steps > 0)
        this.interval = this.duration / this.steps;

    // Set up the array of panels we want to animate.

    var panels = accordion.getPanels();
    for (var i = 0; i < panels.length; i++)
    {
        var p = panels[i];
        var c = accordion.getPanelContent(p);
        if (c)
        {
            var h = c.offsetHeight;
            if (h == undefined)
                h = 0;
            if (p == panel || h > 0)
            {
                var obj = new Object;
                obj.panel = p;
                obj.content = c;
                obj.fromHeight = h;
                obj.toHeight = (p == panel) ? (accordion.useFixedPanelHeights ? accordion.fixedPanelHeight : c.scrollHeight) : 0;
                obj.increment = (obj.toHeight - obj.fromHeight) / this.steps;
                obj.overflow = c.style.overflow;
                this.panelData.push(obj);

                c.style.overflow = "hidden";
                c.style.height = h + "px";
            }
        }
    }
};

Spry.Widget.Accordion.PanelAnimator.prototype.start = function()
{
    var self = this;
    this.timer = setTimeout(function() {
        self.stepAnimation();
    }, this.interval);
};

Spry.Widget.Accordion.PanelAnimator.prototype.stop = function()
{
    if (this.timer)
    {
        clearTimeout(this.timer);

        // If we're killing the timer, restore the overflow
        // properties on the panels we were animating!

        if (this.stepCount < this.steps)
        {
            for (i = 0; i < this.panelData.length; i++)
            {
                obj = this.panelData[i];
                obj.content.style.overflow = obj.overflow;
            }
        }
    }

    this.timer = null;
};

Spry.Widget.Accordion.PanelAnimator.prototype.stepAnimation = function()
{
    ++this.stepCount;

    this.animate();

    if (this.stepCount < this.steps)
        this.start();
    else if (this.onComplete)
        this.onComplete();
};

Spry.Widget.Accordion.PanelAnimator.prototype.animate = function()
{
    var i, obj;

    if (this.stepCount >= this.steps)
    {
        for (i = 0; i < this.panelData.length; i++)
        {
            obj = this.panelData[i];
            if (obj.panel != this.panel)
                obj.content.style.height = "0px";
            obj.content.style.overflow = obj.overflow;
            obj.content.style.height = obj.toHeight + "px";
        }
    }
    else
    {
        for (i = 0; i < this.panelData.length; i++)
        {
            obj = this.panelData[i];
            obj.fromHeight += obj.increment;
            obj.content.style.height = obj.fromHeight + "px";
        }
    }
};

图片资源:




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值