从dom节点到dom节点的javascript/css动画

jan*_*mon 32 html javascript css animation

ng-animate-ref允许创建从一个dom节点到另一个dom节点的转换.

NG-动画使用所有的CSS样式等position,font-size,font-color从第一DOM元素和第二DOM元素和更多,并创建一个CSS 3动画的元素移动从状态a到状态b.

这正是我需要的,但不幸的是我不能在当前项目中使用Angular 1.

是否有任何可重用的方法来实现相同的css3动画而不将所有样式从我的CSS文件移动到javascript?

要说明问题,请参阅以下示例.正如您所看到的,该示例根本没有自定义的javascript动画代码,只有javascript代码处理从列表a到的状态逻辑切换元素b.

动画定义是用纯CSS编写的.

演示:https:
//codepen.io/jonespen/pen/avBZpO/

预习:
演示预览

TTC*_*TCC 18

当然,jQuery animate可以在没有任何插件的情况下实现它.

也许代码行不多,但它们确实有一些复杂性.

是你想要的(ps:jquery-ui仅用于改变颜色).

$(document).ready(function() {
  var animating = false,
    durtion = 300;
  $('.items').on("click", ".items-link", function() {
    if (animating) return;
    animating = true;
    var $this = $(this),
      dir = $this.parent().hasClass("items-l") ? "r" : "l",
      color = dir == "l" ? "#0000FF" : "#F00000",
      index = $this.attr("data-index");

    var toItems = $('.items-' + dir),
      itemsLinks = toItems.find(".items-link"),
      newEle = $this.clone(true),
      nextEle = $this.next(),
      toEle;

    if (itemsLinks.length == 0) {
      toItems.append(newEle)
    } else {
      itemsLinks.each(function() {
        if ($(this).attr("data-index") > index) {
          toEle = $(this);
          return false;
        }
      });
      if (toEle) {
        toEle.before(newEle).animate({
          "marginTop": $this.outerHeight()
        }, durtion, function() {
          toEle.css("marginTop", 0);
        });
      } else {
        toEle = itemsLinks.last();
        toEle.after(newEle)
      }
    }

    nextEle && nextEle.css("marginTop", $this.outerHeight())
      .animate({
        "marginTop": 0
      }, durtion);

    var animate = newEle.position();
    animate["background-color"] = color;
    newEle.hide() && $this.css('position', 'absolute')
      .animate(animate, durtion, function() {
        newEle.show();
        $this.remove();
        animating = false;
      });
  });
});
Run Code Online (Sandbox Code Playgroud)
.items {
  padding: 0;
  -webkit-transition: 300ms linear all;
  transition: 300ms linear all;
}
.items.items-l {
  float: left
}
.items.items-r {
  float: right
}
.items.items-l a {
  background: #0000FF
}
.items.items-r a {
  background: #F00000
}
.items a,
.items-link {
  color: #fff;
  padding: 10px;
  display: block;
}
.main {
  width: 100%;
}
Run Code Online (Sandbox Code Playgroud)
<script type="text/javascript" src="//code.jquery.com/jquery-1.9.1.js">
</script>
<script type="text/javascript" src="//code.jquery.com/ui/1.9.2/jquery-ui.js">
</script>
<link rel="stylesheet" type="text/css" href="//code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css">
<div class="main">
  <div class="items items-l">
    <a class="items-link" data-index="1" href="#">Item 1</a>
    <a class="items-link" data-index="2" href="#">Item 2</a>
    <a class="items-link" data-index="3" href="#">Item 3</a> 
    <a class="items-link" data-index="4" href="#">Item 4</a>
    </div>
    <div class="items items-r">
      <a href="#" class="items-link" data-index="5">Item 5</a>
      <a href="#" class="items-link" data-index="6">Item 6</a>
      <a href="#" class="items-link" data-index="7">Item 7</a>
      <a href="#" class="items-link" data-index="8">Item 8</a>
  </div>
  
Run Code Online (Sandbox Code Playgroud)


use*_*291 8

一个简单的JavaScript解决方案,使用:

  • HTMLElement.getBoundingClientRect 找出元素的新旧位置之间的差异
  • css transition动画
  • css transform翻译

方法说明:

核心思想是让浏览器只计算/重排DOM 一次.我们将自己处理初始状态和新状态之间的转换.

通过仅转换(a)GPU加速transform属性,在(b)少量元素(所有<li>元素)上,我们将尝试确保高帧速率.

// Store references to DOM elements we'll need:
var lists = [
  document.querySelector(".js-list0"),
  document.querySelector(".js-list1")
];
var items = Array.prototype.slice.call(document.querySelectorAll("li"));

// The function that triggers the css transitions:
var transition = (function() { 
  var keyIndex = 0,
      bboxesBefore = {},
      bboxesAfter = {},
      storeBbox = function(obj, element) {
        var key = element.getAttribute("data-key");
        if (!key) {
          element.setAttribute("data-key", "KEY_" + keyIndex++);
          return storeBbox(obj, element);
        }
        
        obj[key] = element.getBoundingClientRect();
      },
      storeBboxes = function(obj, elements) {
        return elements.forEach(storeBbox.bind(null, obj));
      };
  
  // `action` is a function that modifies the DOM from state *before* to state *after*
  // `elements` is an array of HTMLElements which we want to monitor and transition
  return function(action, elements) {
    if (!elements || !elements.length) {
      return action();
    }
    
    // Store old position
    storeBboxes(bboxesBefore, elements);
    
    // Turn off animation
    document.body.classList.toggle("animated", false);
    
    // Call action that moves stuff around
    action();
    
    // Store new position
    storeBboxes(bboxesAfter, elements);
    
    // Transform each element from its new position to its old one
    elements.forEach(function(el) {
      var key = el.getAttribute("data-key");
      var bbox = {
        before: bboxesBefore[key],
        after: bboxesAfter[key]
      };
      
      var dx = bbox.before.left - bbox.after.left;
      var dy = bbox.before.top - bbox.after.top;
      
      el.style.transform = "translate3d(" + dx + "px," + dy + "px, 0)";
    });

    // Force repaint
    elements[0].parentElement.offsetHeight;

    // Turn on CSS animations
    document.body.classList.toggle("animated", true);
   
    // Remove translation to animate to natural position
    elements.forEach(function(el) {
      el.style.transform = "";
    });
  };
}());

// Event handler & sorting/moving logic
document.querySelector("div").addEventListener("click", function(e) {
  var currentList = e.target.getAttribute("data-list");
  if (currentList) {
    var targetIndex = e.target.getAttribute("data-index");
    var nextIndex = 0;

    // Get the next list from the lists array
    var newListIndex = (+currentList + 1) % lists.length;
    var newList = lists[newListIndex];
    
    for (nextIndex; nextIndex < newList.children.length; nextIndex++) {
      if (newList.children[nextIndex].getAttribute("data-index") > targetIndex) {
        break;
      }
    }
    
    // Call the transition
    transition(function() {
      newList.insertBefore(e.target, newList.children[nextIndex]);
      e.target.setAttribute("data-list", newListIndex);
    }, items);
  }
});
Run Code Online (Sandbox Code Playgroud)
div { display: flex; justify-content: space-between; }


.animated li {
  transition: transform .5s ease-in-out;
}
Run Code Online (Sandbox Code Playgroud)
<h2>Example</h2>
<div>
  <ul class="js-list0">
    <li data-index="0" data-list="0">Item 1</li>
    <li data-index="3" data-list="0">Item 2</li>
    <li data-index="5" data-list="0">Item 4</li>
    <li data-index="7" data-list="0">Item 6</li>
  </ul>

  <ul class="js-list1">
    <li data-index="4" data-list="1">Item 3</li>
    <li data-index="6" data-list="1">Item 5</li>
  </ul>
</div>
Run Code Online (Sandbox Code Playgroud)


编辑:

要添加对您要设置动画的其他属性的支持,请遵循以下4步方法:

  1. 将css规则添加到.animated transition属性:

    transition: transform .5s ease-in-out,
                background-color .5s ease-in-out;
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在修改DOM之前存储属性计算样式:

    obj[key].bgColor = window
      .getComputedStyle(element, null)
      .getPropertyValue("background-color");
    
    Run Code Online (Sandbox Code Playgroud)
  3. 修改后,快速设置属性的临时覆盖,就像我们已经为transformprop 做的那样.

    el.style.backgroundColor = bbox.before.bgColor;
    
    Run Code Online (Sandbox Code Playgroud)
  4. 打开css动画后,删除临时覆盖以触发css转换:

    el.style.backgroundColor = "";
    
    Run Code Online (Sandbox Code Playgroud)

在行动:http://codepen.io/anon/pen/pELzdr

请注意,css过渡在某些属性上运行得非常好,比如transformopacity,虽然它们可能在其他属性上表现更差(例如height,通常会触发重新绘制).确保监控帧速率以防止出现性能问题!


小智 1

我受到之前所有优秀帖子的启发,并将其变成了一个库,允许在没有角度的情况下使用 ng-animate。

该库名为Animorph

我几乎没有使用自定义 JavaScript 代码就解决了所描述的示例(因为重要的部分都在库中)。

请注意,现在它不会对列表进行排序,而仅关注动画部分。

代码笔:http://codepen.io/claudiobmgrtnr/pen/NRrYaQ

JavaScript:

  $(".left").on("click", "li.element", function() {
    $(this).amAppendTo('.right', {
      addClasses: ['element--green'],
      removeClasses: ['element--golden']
    });
  });
  $(".right").on("click", "li.element", function() {
    $(this).amPrependTo('.left', {
      addClasses: ['element--golden'],
      removeClasses: ['element--green']
    });
  });
Run Code Online (Sandbox Code Playgroud)

社会保障体系:

body {
  margin: 0;
  width: 100%;
  &:after {
    content: '';
    display: table;
    width: 100%;
    clear: both;
  }
}

ul {
  list-style-type: none;
  padding: 0;
}

.element {
  width: 100px;
  height: 30px;
  line-height: 30px;
  padding: 8px;
  list-style: none;
  &--golden {
    background: goldenrod;
  }
  &--green {
    background: #bada55;
  }
  &.am-leave {
    visibility: hidden;
  }
  &.am-leave-prepare {
    visibility: hidden;
  }
  &.am-leave-active {
    height: 0;
    padding-top: 0;
    padding-bottom: 0;
  }
  &.am-enter {
    visibility: hidden;
  }
  &.am-enter-prepare {
    height: 0;
    padding-top: 0;
    padding-bottom: 0;
  }
  &.am-enter-active {
    height: 30px;
    padding-top: 8px;
    padding-bottom: 8px;
  }
  &.am-enter,
  &.am-move,
  &.am-leave {
    transition: all 300ms;
  }
}

.left {
  float: left;
}

.right {
  float: right;
}
Run Code Online (Sandbox Code Playgroud)