FLIP 翻转动画

文章介绍了FLIP技术,一种用于优化动画性能和简化开发的技术,涉及DOM操作、Fist(初始位置)、Last(终止位置)、Invert(计算差异并应用transform)和Play(添加过渡效果)的概念。文中展示了如何在实际项目中应用FLIP技术处理蒙层逻辑和DOM事件。
摘要由CSDN通过智能技术生成

FLIP技术可以让我们的动画更加流畅,同时也能降低复杂动画的开发难度

名词解释,FLIP是几个英文单词的缩写,简单介绍一下:

F:Fist —— 一个元素的起始位置

L:Last —— 另一个元素的终止位置,注意另一个这个词,后面会有具体代码的体现

I:Invert —— 计算"F"与"L"的差异,包括位置,大小等,并将差异用transform属性,添加到终止元素上,让它回到起始位置,也是此项技术的核心

P:Play —— 添加transtion 过渡效果,清除Invert阶段添加进来transform,播放动画

1、处理一下蒙层的逻辑

我们先把外部简单逻辑处理一下,根据效果,有一个点击蒙层关闭的操作,代码如下:

let mask_dom = document.getElementsByClassName("mask")[0]
let pic_dom = document.getElementById('pic')
mask_dom.addEventListener("click", (e) => {
  mask_dom.style.display = 'none'
  pic_dom.innerHTML = ''
})

需要注意的是,关闭的同时我们还要清理承载放大图的div

2、dom比较多使用事件代理

let container_dom = document.getElementsByClassName("container")[0]
container_dom.addEventListener("click", (e) => {
  //获得点击位置的dom节点
let boxDom = e.target
//判断点击的是不是模拟图片的dom
if(boxDom.className.indexOf('box') === -1){
  return
}
// 打开蒙层
  mask_dom.style.display = 'block'
//克隆被点击的节点
  let cloneDom = boxDom.cloneNode(true)
})

3、Fist获得起始位置dom的位置信息

  //第一步、获得初始位置信息
let firstInfo =  boxDom.getBoundingClientRect()

4、Last获取结束时的位置信息

 //第二步、获取结束时的位置信息——添加全局居中样式
  cloneDom.className = cloneDom.className + " picture-zoom-in"
//第二步、获取结束时的位置信息——放到容器中
  pic_dom.appendChild(cloneDom)
//第二步、获取结束时的位置信息
let lastInfo = cloneDom.getBoundingClientRect()

5、Invert计算差异

//第三步、计算变化的数据数据 
let invertInfo = {
  x: firstInfo.x - lastInfo.x,
  y: firstInfo.y - lastInfo.y,
}
// 第三步、计算变化的数据数据 - 将克隆节点赋值变化的数据 回到初始位置 
//特别说明 由于有scale,会导致transformOrigin发生变化,在修改scale时需要将transformOrigin归零
cloneDom.style.transformOrigin = "0 0"
cloneDom.style.transform = `scale(1) translate(calc(-100% + ${invertInfo.x}px),calc(-100% +  ${invertInfo.y}px))`

6、play播放动画

//第四步、设定过度动画,删除第三步的transform
setTimeout(() => {
  cloneDom.style.transition = "all .5s"
  cloneDom.style.transformOrigin = ''
  cloneDom.style.transform = ``
})

 下面是全部代码:

<!DOCTYPE html>
<html lang="en">
 
<head>
 <meta charset="UTF-8">
 <meta http-equiv="X-UA-Compatible" content="IE=edge">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>FLIP-demo</title>
 <style>
 .container {
 display: flex;
 flex-wrap: wrap;
 text-align: center;
        }
 
 .box {
 
 border:1px solid #ccc;
 margin-left: 10px;
 margin-top: 10px;
        }
 .box_0{
 width: 200px;
 height: 250px;
 background-color: #ffa39e;
 color: #000000;
 line-height:250px;
        }
 
 .box_1 {
 width: 160px;
 height: 210px;
 background-color:#ffd8bf;
 line-height: 210px;
 
        }
 .box_2 {
 width: 190px;
 height: 270px;
 background-color:#ffd591;
 line-height:270px;
        }
 .box_3 {
 width: 210px;
 height: 300px;
 background-color:#ffe58f;
 line-height:300px;
        }
 .box_4 {
 height: 160px;
 width: 210px;
 background-color:#780650;
 color:#ffffff;
 line-height:160px;
        }
 .box_5 {
 height: 190px;
 width: 270px;
 background-color:#22075e;
 color:#ffffff;
 line-height:190px;
        }
 .box_6 {
 height: 210px;
 width: 300px;
 background-color:#061178;
 color:#ffffff;
 line-height:210px;
        }
 .mask{
 position: fixed;
 width: 100%;
 height: 100%;
 background: #000000;
 opacity: 0.7;
 z-index: 1;
 display: none;
 text-align: center;
        }
 .picture-zoom-in{
 position: fixed;
 z-index: 2;
 left: 50%;
 top: 50%;
 transform: translate(-50% ,-50%) scale(2) ;
 text-align: center;
        }
 </style>
</head>
 
<body>
 <!-- 蒙层 -->
 <div class="mask">
 
 </div>
 <!-- 放大图片的容器 -->
 <div id="pic">
 
 </div>
 <!-- 图片容器及列表 -->
 <div class="container">
 <div class="box box_0">200px*250px</div>
 <div class="box box_0">200px*250px</div>
 <div class="box box_0">200px*250px</div>
 <div class="box box_0">200px*250px</div>
 <div class="box box_1">160px*210px</div>
 <div class="box box_2">190px*270px</div>
 <div class="box box_3">210px*300px</div>
 <div class="box box_4">210px*160px</div>
 <div class="box box_5">270px*190px</div>
 <div class="box box_6">300px*210px</div>
 </div>
 
 <script>
 let container_dom = document.getElementsByClassName("container")[0]
 let mask_dom = document.getElementsByClassName("mask")[0]
 let pic_dom = document.getElementById('pic')
 
 mask_dom.addEventListener("click", (e) => {
 mask_dom.style.display = 'none'
 pic_dom.innerHTML = ''
        })
 
 //dom 比较多采用事件代理
 container_dom.addEventListener("click", (e) => {
 //获得点击位置的dom节点
 let boxDom = e.target
 //判断点击的是不是模拟图片的dom
 if(boxDom.className.indexOf('box') === -1){
 return
            }
 // 打开蒙层
 mask_dom.style.display = 'block'
 
 //克隆被点击的节点
 let cloneDom = boxDom.cloneNode(true)
 
 //第一步、获得初始位置信息
 let firstInfo =  boxDom.getBoundingClientRect()
 
 //第二步、获取结束时的位置信息——添加全局居中样式
 cloneDom.className = cloneDom.className + " picture-zoom-in"
 //第二步、获取结束时的位置信息——放到容器中
 pic_dom.appendChild(cloneDom)
 //第二步、获取结束时的位置信息
 let lastInfo = cloneDom.getBoundingClientRect()
 
 //第三步、计算变化的数据数据 
 let invertInfo = {
 x: firstInfo.x - lastInfo.x,
 y: firstInfo.y - lastInfo.y,
            }
 // 第三步、计算变化的数据数据 - 将克隆节点赋值变化的数据 回到初始位置 
 //特别说明 由于有scale,会导致transformOrigin发生变化,在修改scale时需要将transformOrigin归零
 cloneDom.style.transformOrigin = "0 0"
 cloneDom.style.transform = `scale(1) translate(calc(-100% + ${invertInfo.x}px),calc(-100% + ${invertInfo.y}px))`
 //第四步、设定过度动画,删除第三步的transform
 setTimeout(() => {
 cloneDom.style.transition = "all .5s"
 cloneDom.style.transformOrigin = ''
 cloneDom.style.transform = ``
            })
 
        })
 
 </script>
</body>
 
</html>

 

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柑橘乌云_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值