9

请看看这个小提琴:http: //jsfiddle.net/dhcyA/

尝试单击一个块。我想要的是当其他元素消失时,选定的块将动画/缓和到他的给定位置,而不是像现在这样跳跃。然后,当再次单击该框时,相同的动画会自行重复,但随后又回到原位。

也许要记住:
我使用的是响应式设计,这意味着这些块在缩放窗口后可以是垂直和水平的。

对小提琴或建议的任何重新修改都会很棒!

4

5 回答 5

7

这是我的解决方案。

在您现有的标记上,我添加了一个包装器划分来计算包装器内框的位置。像这样

<div id="wrapper">
    <div class="block">
        <h2>I'm block 1</h2>
    </div>
    ....
</div>

为了保持块的流动性,我创建了一个函数来将块定位在包装器上。这是块位置的函数:

var reposition = function() {
    wrapper = $("#wrapper");
    console.log(wrapper.innerWidth());
    pLeft = 0;
    pTop = 0;
    maxRowHeight = 0;
    $(".block").each(function(){
        if($(this).data('active')) {
            $(this).data('top', pTop);
            $(this).data('left', pLeft);
        } else {
            $(this).stop(0,0).animate({
              'top' : pTop + 'px',
              'left' : pLeft + 'px'
            });
        }
            pLeft += $(this).outerWidth() + parseInt($(this).css('marginLeft'));
            if($(this).height() > maxRowHeight) maxRowHeight = $(this).outerHeight() + parseInt($(this).css('marginTop')); //Find out the longest block on the row

            if(pLeft + $(this).next().outerWidth() + parseInt($(this).next().css('marginLeft')) >= wrapper.innerWidth()) {
               pLeft = 0;
               pTop += maxRowHeight;
               maxRowHeight = 0;
            }

    });    
};

最后,切换块的脚本

$(".block").click(function() {

    $(this).siblings().slideToggle('slow'); //Toggle other blocks

    if(!$(this).data('active')){ //if the block is not active
        $(this).data('left', $(this).position().left); //sets its left
        $(this).data('top', $(this).position().top);   // and top position
        $(this).animate({ //animate at the top and bottom
            top:0,
            left:0
        },'slow');

        $(this).data('active',true);

    }else{

        $(this).animate({ //animate to its last known position
            top:$(this).data('top'),
            left:$(this).data('left')
        },'slow');

        $(this).data('active',false);
    }
});

演示

以下是此解决方案提供的内容:

  • 记住最后一个位置并逐渐动画到/从这个位置开始
  • 块位置在加载和每次调整大小时计算和动画
  • 尽管使用绝对位置,但仍会发生重新定位,$(window).resize()从而保持块的流动
  • 支持可变高度
  • 现有标记和 CSS 的微小变化

还修复了 Gaby 扩展的两个问题

  • 独立核算每个区块保证金
  • 调整大小后重新计算元素的位置
于 2012-10-29T03:03:55.747 回答
5

最终更新

这是一个完整的工作解决方案(在我看来非常简单),用 JS 设置定位(一个简单的计算)和其余的 CSS 转换..

演示在 http://jsfiddle.net/gaby/pYdKB/3/

它保持了任意数量元素的流动性float:left并适用于任意数量的元素,并且您可以保留:nth-child样式,如果您想让多个元素可见,它也可以工作。

javascript

var wrapper = $('.wrapper'),
    boxes = wrapper.children(),
    boxWidth = boxes.first().outerWidth(true),
    boxHeight = boxes.first().outerHeight(true); 

function rePosition(){
    var w = wrapper.width(),
        breakat = Math.floor( w / boxWidth ); // calculate fluid layout, just like float:left

    boxes
        .filter(':not(.go)')
        .each(function(i){
            var matrixX = ((i)%breakat)+1,
                matrixY = Math.ceil((i+1)/breakat);

            $(this).css({
                left:(matrixX-1) * boxWidth ,
                top: (matrixY-1) * boxHeight
            });
        });
}

$('.box').click(function(){
    $(this)
        .siblings()
        .toggleClass('go');// just add the go class, and let CSS handle the rest

    rePosition(); // recalculate final positions and let CSS animate the boxes
});

$(window).resize(rePosition);
$(window).trigger('resize');

CSS

.wrapper{
    position:relative;
}

.box{
    width:200px;
    height:100px;
    position:absolute;
    margin:5px;
    cursor:pointer;
    overflow:hidden;
    text-align: center;
    line-height: 100px;

        -moz-transition-property: top,left,width,height;
     -webkit-transition-property: top,left,width,height;
         -ms-transition-property: top,left,width,height;
          -o-transition-property: top,left,width,height;
             transition-property: top,left,width,height;

        -moz-transition-duration: 1s;
     -webkit-transition-duration: 1s;
         -ms-transition-duration: 1s;
          -o-transition-duration: 1s;
             transition-duration: 1s;
}

.go{
    height:0;
    width:0;
}

注意:正如@Athari 在评论中正确提到的那样,您应该包括所有浏览器前缀以获得最广泛的支持。(我最初的回答只包括 moz / webkit 和标准)


原始答案

您不能直接使用当前的 HTML 结构来执行此操作。浮动概念不支持它。

但如果你能负担得起额外的包装,那没问题。

只需滑动额外包装元素的内容..

float代码放在包装元素上并使用

$(document).ready(function() {

    $(".block-wrapper").click(function() {
        $(this).siblings().find('.block').slideToggle("slow");
    });

});

演示在 http://jsfiddle.net/gaby/t8GNP/


更新#1

如果您需要将点击的元素移动到左上角和后退,那么您无法使用 CSS 真正做到这一点。

您将需要手动定位它们(​​通过 JS),设置 CSS 过渡(或 jquery),并在单击后应用新位置。

稍后您可能希望不止一个保持可见并重新定位..

所以你可能想看看伟大的同位素插件,它可以处理这个和许多更多的情况/布局

于 2012-10-28T21:31:59.127 回答
3

这是我的版本:http: //jsfiddle.net/selbh/dhcyA/92/ (仅更改了 javascript,并且它是响应式的)

$(document).ready(function() {

    $(".block").click(function() {
        var $this = $(this);
        var pos = $this.offset();
        var $siblings = $(this).siblings().add(this);
        var marginTop = $this.css('marginTop').replace(/[^-\d\.]/g, '');
        var marginLeft = $this.css('marginLeft').replace(/[^-\d\.]/g, ''); 

        var $clone = $this.clone();

        $siblings.slideToggle("slow");

        $clone.css({
            position: 'absolute',
            left: pos.left - marginLeft,
            top: pos.top - marginTop,
            'background-color': $this.css('background-color')
        });

        $('body').append($clone);

        $this.css('opacity', 0);

        $clone.animate({
            'left': 0,
            'top': 0
        });


        $clone.click(function() {
            $siblings.slideToggle("slow", function() {
                $clone.remove();
                $this.css('opacity', 1);
            });

            $clone.animate({
                left: pos.left - marginLeft,
                top: pos.top - marginTop
            });
        });


    });

});​
于 2012-11-03T22:44:04.163 回答
2

大挑战!

新版本:

这是一个更好的版本,因为它使块保持在它们的行中。我添加了一个css函数,以便您的nth-child样式甚至可以应用于行中。甚至保持相同的 HTML 结构。

演示:http: //jsfiddle.net/MadLittleMods/fDDZB/23/

这个新版本的 jQuery 看起来像:

$('.block').on('click', function() {
    var block = $(this);

    // Keep the blocks in line
    makeRows($('body'));

    $('.block').not(this).each(function() {

        // If sibling on the same level, horizontal toggle
        // We also want ignore the toggleMethod if it is shown because we might need to reassign
        if (($(this).position().top == block.position().top && (($(this).data('toggle') == -1) || $(this).data('toggle') == null)) || ($(this).data('toggle') != -1 && $(this).data('toggleMethod') == 'side'))
        {
            $(this).data('toggleMethod', 'side');

            // Hide block
            if ($(this).data('toggle') == -1 || $(this).data('toggle') == null)
            {
                // Set properties for later use in show block
                $(this).data('overflowBefore', $(this).css('overflow'));
                $(this).css('overflow', 'hidden');
                $(this).data('marginBefore', $(this).css('margin'));

                var width = $(this).width();
                $(this).animate({
                    width: 0,
                    margin: 0
                }, function() {
                    $(this).data('toggle', width);
                });
            }
            // Show block
            else
            {
                $(this).css('overflow', $(this).data('overflowBefore'));

                $(this).animate({
                    width: $(this).data('toggle'),
                    margin: $(this).data('marginBefore')
                }, function() {
                    $(this).data('toggle', -1);
                });
            }
        }
        // Do a normal vertical toggle
        else 
        {
            $(this).data('toggleMethod', 'top');
            $(this).slideToggle('slow');
        }
    });

});

// Make rows to make the blocks in line
function makeRows(container)
{
    // Make rows so that the elements stay where they should
    var containerWidth = container.width();
    var currentRowWidth = 0;

    // Add styles first so nothing gets messed up
    container.children().each(function() {
        var itemCSS = css($(this));
        $(this).css(itemCSS);
    });

    // Now assemble the rows
    container.children().each(function() {

        var blockWidth = $(this).outerWidth() + parseInt($(this).css('margin-left')) + parseInt($(this).css('margin-right'));

        if((currentRowWidth + blockWidth) < containerWidth)
        {
            currentRowWidth += blockWidth;
        }
        else
        {
            Array.prototype.reverse.call($(this).prevUntil('.row')).wrapAll('<div class="row"></div>');
            $(this).prev().append('<div class="row_clear" style="clear: both;"></div>');

            currentRowWidth = 0;
        } 
    });    
}

// Remove the rows added
function deleteRows()
{
    var content = $('.row').contents()
    $('.row').replaceWith(content);

    $('.row_clear').remove();
}

$(window).resize(function() {
    deleteRows();
});



// Functions courtesy of marknadal
// https://stackoverflow.com/a/5830517/796832
function css(a)
{
    var sheets = document.styleSheets, o = {};
    for(var i in sheets) {
        var rules = sheets[i].rules || sheets[i].cssRules;
        for(var r in rules) {
            if(a.is(rules[r].selectorText)) {
                o = $.extend(o, css2json(rules[r].style), css2json(a.attr('style')));
            }
        }
    }
    return o;
}

function css2json(css)
{
    var s = {};
    if(!css) return s;
    if(css instanceof CSSStyleDeclaration) {
        for(var i in css) {
            if((css[i]).toLowerCase) {
                s[(css[i]).toLowerCase()] = (css[css[i]]);
            }
        }
    } else if(typeof css == "string") {
        css = css.split("; ");          
        for (var i in css) {
            var l = css[i].split(": ");
            s[l[0].toLowerCase()] = (l[1]);
        };
    }
    return s;
}

我添加了一个makeRowsdeleteRows函数,以便块保持在它们的行中,而不是变小并移动到上面的行中。每当窗口调整大小时,我都会调用deleteRows它,以便它可以保持响应式布局。然后,如果需要切换块,我会重新创建行。

csscss2json功能是由marknadal提供的



旧版:

我想出了一个解决方案,.animate以便它可以水平缓解。

这是一个演示:http: //jsfiddle.net/MadLittleMods/fDDZB/8/

jQuery 看起来像:

$('.block').on('click', function() {
    var block = $(this);
    $(this).siblings().each(function() {
        // If sibling on the same level, horizontal toggle
        // We also want ignore the toggleMethod if it is shown because we might need to reassign
        if (($(this).position().top == block.position().top && ($(this).data('toggle') == -1) || $(this).data('toggle') == null) || ($(this).data('toggle') != -1 && $(this).data('toggleMethod') == 'side'))
        {
            $(this).data('toggleMethod', 'side');

            // Hide block
            if ($(this).data('toggle') == -1 || $(this).data('toggle') == null)
            {
                // Set properties for later use in show block
                $(this).data('overflowBefore', $(this).css('overflow'));
                $(this).css('overflow', 'hidden');
                $(this).data('marginBefore', $(this).css('margin'));

                var width = $(this).width();
                $(this).animate({
                    width: 0,
                    margin: 0
                }, function() {
                    $(this).data('toggle', width);
                });
            }
            // Show block
            else
            {
                $(this).css('overflow', $(this).data('overflowBefore'));

                $(this).animate({
                    width: $(this).data('toggle'),
                    margin: $(this).data('marginBefore')
                }, function() {
                    $(this).data('toggle', -1);
                });
            }
        }
        // Do a normal vertical toggle
        else 
        {
            $(this).data('toggleMethod', 'top');
            $(this).slideToggle('slow');
        }
    });
});​

关键是分离被切换的块,.slideToggle因为.animate你必须在它们显示和隐藏时应用相同的块。

于 2012-10-28T22:37:16.927 回答
2

我有点困(这里是凌晨 2:30)所以我把一半完成的答案留在这里给你一个想法(我在 30 分钟内完成了,所以我想再多 30 分钟你就能得到一些非常好的东西)

http://jsfiddle.net/LuL2s/2/

诀窍来自块持有者,它制作缓动动画并在它们出现和消失时产生差异

JS

$(document).ready(function() {
    var open = true;
    $(".block").click(function() {
            var $this = $(this);
            var count = 0;
        if (open) {
            $this.parent().siblings().children().slideToggle("slow", function(){
                if (count++ == 2) {                 
                    $this.parent().siblings().animate({width: 'toggle', height:'toggle'});
                }
            });
        } else {
            $this.parent().siblings().animate({width: 'toggle', height:'toggle'}, function(){
                if (count++ == 2) {                 
                    $this.parent().siblings().children().slideToggle("slow");                
                }
            });

        }
        open = !open;                      
    });

});

HTML

<div class="block-holder">
    <div class="block">
        <h2>I'm block 1</h2>
    </div>
</div>

<div class="block-holder">
    <div class="block">
        <h2>I'm block 2</h2>
    </div>
</div>

<div class="block-holder">
    <div class="block">
        <h2>I'm block 3</h2>
    </div>
</div>

<div class="block-holder">
    <div class="block">
        <h2>I'm block 4</h2>
    </div>
</div>

CSS

.block {
    width: 100%;
    height: 100%;
    text-align: center;
    line-height: 100px;
    cursor: pointer;
}
.block-holder:nth-child(1) .block {
    background: green;
}
.block-holder:nth-child(2) .block {
    background: red;
}
.block-holder:nth-child(3) .block {
    background: orange;
}
.block-holder:nth-child(4) .block {
    background: pink;
}

.block-holder {
    width: 200px;
    height: 100px;
    float: left;
    margin: 20px;
}
于 2012-10-29T01:33:09.573 回答