请看看这个小提琴:http: //jsfiddle.net/dhcyA/
尝试单击一个块。我想要的是当其他元素消失时,选定的块将动画/缓和到他的给定位置,而不是像现在这样跳跃。然后,当再次单击该框时,相同的动画会自行重复,但随后又回到原位。
也许要记住:
我使用的是响应式设计,这意味着这些块在缩放窗口后可以是垂直和水平的。
对小提琴或建议的任何重新修改都会很棒!
请看看这个小提琴:http: //jsfiddle.net/dhcyA/
尝试单击一个块。我想要的是当其他元素消失时,选定的块将动画/缓和到他的给定位置,而不是像现在这样跳跃。然后,当再次单击该框时,相同的动画会自行重复,但随后又回到原位。
也许要记住:
我使用的是响应式设计,这意味着这些块在缩放窗口后可以是垂直和水平的。
对小提琴或建议的任何重新修改都会很棒!
这是我的解决方案。
在您现有的标记上,我添加了一个包装器划分来计算包装器内框的位置。像这样
<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 扩展的两个问题
- 独立核算每个区块保证金
- 调整大小后重新计算元素的位置
最终更新
这是一个完整的工作解决方案(在我看来非常简单),用 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),并在单击后应用新位置。
稍后您可能希望不止一个保持可见并重新定位..
所以你可能想看看伟大的同位素插件,它可以处理这个和许多更多的情况/布局
这是我的版本: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
});
});
});
});
大挑战!
这是一个更好的版本,因为它使块保持在它们的行中。我添加了一个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;
}
我添加了一个makeRows
和deleteRows
函数,以便块保持在它们的行中,而不是变小并移动到上面的行中。每当窗口调整大小时,我都会调用deleteRows
它,以便它可以保持响应式布局。然后,如果需要切换块,我会重新创建行。
css
和css2json
功能是由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
你必须在它们显示和隐藏时应用相同的块。
我有点困(这里是凌晨 2:30)所以我把一半完成的答案留在这里给你一个想法(我在 30 分钟内完成了,所以我想再多 30 分钟你就能得到一些非常好的东西)
诀窍来自块持有者,它制作缓动动画并在它们出现和消失时产生差异
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;
}