如何在溢出:隐藏区域添加DOM元素?

时间:2014-07-25 08:53:14

标签: jquery html css dom

我正在创建一个每年显示表格数据的控件。类型为table的DOM元素已添加到div设置为overflow的{​​{1}}。表格hidden设置为positionrelative的{​​{1}}被固定为一个表的高度,因此一次只能看到一个表。

我有一个向前和向后翻页的分页机制,并通过更改表的height属性来动画转换,以使表格数据看起来像是向上和向下滑动。就像经典日历一样。

我面临的问题是:在添加新元素时,我想将其添加到现有表格顶部的div-content的隐藏部分,以便在将其添加到视图后将其设置为视图DOM树。这可能没有“黑客”吗?

我尝试更改表格的div属性,然后将其添加到top,但不会将它们放入top的{​​{1}}部分

我怎样才能做到这一点?

这就是我目前在jsFiddle中所拥有的:http://jsfiddle.net/34v6R/2/

更新

我也试过使用hide()和slideDown()但是slideDown的动画似乎不是很流畅(至少在jsfiddle中)

div

http://jsfiddle.net/34v6R/6

2 个答案:

答案 0 :(得分:1)

您指定的尺寸如何?如果你没有使用"身高:500px"或者其他一些,当你向它添加新元素时,div就会被扩展。

答案 1 :(得分:1)

更新了答案

在评论中,你说过

  

我面临的问题是我想要添加新表...

...我确认你希望新表从顶部滑入。

以下原始答案中的大部分讨论都涵盖了我们需要做什么以及我们如何做,这里是一个例子,无论你是从顶部进入表还是从底部进入:{ {3}}

<!DOCTYPE html>
<html>
<head>
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
  <meta charset="utf-8">
  <title>Example</title>
  <style>
    #parent {
      overflow: hidden;
      border: 1px solid black;
      position: relative;
    }
    #parent table {
      position: relative;
      border: 1px solid black;
      width: 100%;
    }
  </style>
</head>
<body>
  <input type="button" value="Back" data-direction="-1">
  <input type="button" value="Forward" data-direction="1">
  <div id="parent">
    <table>
      <tbody>
        <tr><td>Zero</td></tr>
        <tr><td>Zero</td></tr>
        <tr><td>Zero</td></tr>
        <tr><td>Zero</td></tr>
        <tr><td>Zero</td></tr>
        <tr><td>Zero</td></tr>
        <tr><td>Zero</td></tr>
        <tr><td>Zero</td></tr>
        <tr><td>Zero</td></tr>
      </tbody>
    </table>
  </div>
<script>
  (function() {
    "use strict";
    var tables, current, busy;

    tables = prepTables();
    current = 0;
    buttonSetup();
    busy = false;
    enableForIndex(current);

    function prepTables() {
      var zero, one, two;

      // Copy the zero table to create "one" and "two", with varying
      // numbers of rows
      zero = $("#parent table");
      one = zero.clone();
      two = zero.clone();
      one.find("td").html("One");
      one.find("tr").slice(1, 5).clone().appendTo(one.find("tbody"));
      two.find("td").html("Two");
      one.find("tr").slice(1, 3).remove();
      return [zero, one, two];
    }

    function buttonSetup() {
      $("input[type=button]").click(function() {
        var direction = +this.getAttribute("data-direction"),
            index;

        if (!busy) {
          index = current + direction;
          if (index >= 0 && index < tables.length) {
            $("input[type=button").prop("disabled", true);
            busy = true;
            swapTables(index, function() {
              busy = false;
              current = index;
              enableForIndex(current);
            });
          }
        }
      });
    }

    function enableForIndex(index) {
      $("input[data-direction=-1]").prop("disabled", index === 0);
      $("input[data-direction=1]").prop("disabled", index === tables.length - 1);
    }

    function swapTables(index, callback) {
      var parent, height,
          table, tableHeight,
          newTable, newTableHeight,
          bothTables,
          target,
          tableTop,
          newHeight;

      // Get the parent
      parent = $("#parent");

      // Get its height
      height = parent.height();
      parent.css({
        height: height,
        maxHeight: height,
        minHeight: height
      });

      // Get the current table and the desired table
      table = tables[current];
      newTable = tables[index];
      bothTables = table.add(newTable);

      // Remember the current table's top
      tableTop = table.position().top;

      // Insert the new table, change tops if necessary,
      // figure out where our animation should stop
      tableHeight = table.height();
      if (index < current) {
        newTable.insertBefore(table);
        newTableHeight = newTable.height();
        table.css("top", "-=" + newTableHeight);
        newTable.css("top", tableTop - newTableHeight);
        target = tableTop;
      } else {
        newTable.insertAfter(table);
        newTableHeight = newTable.height();
        target = tableTop - newTable.position().top;
      }

      // If the new table is a different size, animate that
      // at the same time, but make sure we finish first
      if (newTableHeight != tableHeight) {
        height += newTableHeight - tableHeight;
        parent.animate({
          height: height,
          maxHeight: height,
          minHeight: height
        }, 1000); // 200ms shorter than the below
      }

      // Animate both tables, get a single callback when the animation is complete
      // (using the `animate` callback, we'd get two -- one for each table -- so
      // we use the promise instead)
      bothTables.animate({
        top: target
      }, 1200).promise().then(function() {
        var newHeight;

        // Complete, detach the old one and put the new one in its normal position
        table.detach().css("top", "");
        newTable.css("top", tableTop);

        // Let the parent assume its natural height again; in
        // theory, this should be the new height we set for it
        // earlier if that needed to change
        parent.css({
          height: "",
          maxHeight: "",
          minHeight: ""
        });

        // Done
        callback();
      });
    }
  })();
</script>
</body>
</html>

原始答案

这里的关键是父div必须在其上设置特定的高度(固定数字,或者因为它是容器高度的某个百分比,等等)。否则,添加第二个表将垂直扩展div,因此不会隐藏第二个表。

如果您希望div具有“自然”高度,那么您只需要在操作过程中修复高度,然后再次释放它。我将在下面给出这个变种。

一旦你完成了,它就相当简单 - 下面代码中的注释解释了。

这是假设div已经有固定高度的版本:Live Copy

var height, table, newTable, target;

// Get the height of the parent div
height = $("#parent").height();

// Get the table
table = $("#parent table");

// Add the new table (in my case I'll just clone that one)
newTable = table.clone();
newTable.find("td").text("Two");
newTable.appendTo("#parent");

// Figure out where we want to stop the animation of `top`
target = table.position().top - newTable.position().top;

// Animate both tables, get a single callback when the animation is complete
// (using the `animate` callback, we'd get two -- one for each table -- so
// we use the promise instead)
newTable.add(table).animate({
  top: target
}, 1200).promise().then(function() {
  // Complete, remove the old one and put the new one in its normal position
  table.remove();
  newTable.css("top", 0);
});

或者如果我们只需要在动画期间修复高度,我们会在开始时测量它,然后修复它,做动画,然后解除它(可能是动画到新的高度):Live Copy

var parent, height, table, newTable, target;

// Get the parent
parent = $("#parent");

// Get its height
height = parent.height();
parent.css({
  height: height,
  maxHeight: height,
  minHeight: height
});

// Get the table
table = parent.find("table");

// Add the new table (in my case I'll just clone that one, and add
// more rows)
newTable = table.clone();
newTable.find("td").text("Two");
newTable.find("tr").slice(1, 5).clone().appendTo(newTable.find("tbody"));
newTable.appendTo(parent);

// Figure out where we want to stop the animation of `top`
target = table.position().top - newTable.position().top;

// Animate both tables, get a single callback when the animation is complete
// (using the `animate` callback, we'd get two -- one for each table -- so
// we use the promise instead)
newTable.add(table).animate({
  top: target
}, 1200).promise().then(function() {
  var newHeight;

  // Complete, remove the old one and put the new one in its normal position
  table.remove();
  newTable.css("top", 0);

  // Let the parent assume its natural height again; if the new table is a
  // different size, just clearing the heights we set would be abrupt, so
  // we animate again
  parent.css({
    height: "",
    maxHeight: "",
    minHeight: ""
  });
  newHeight = parent.height();
  if (newHeight !== height) {
    parent.css({
      height: height,
      maxHeight: height,
      minHeight: height
    }).animate({
      height: newHeight,
      maxHeight: newHeight,
      minHeight: newHeight
    }, function() {
      parent.css({
        height: "",
        maxHeight: "",
        minHeight: ""
      });
    });
  }
});