广告位联系
返回顶部
分享到

CSS3实现类似翻书效果的过渡动画的方法

css 来源:互联网搜集 作者:秩名 发布时间:2019-09-09 16:48:47 人浏览
摘要

在VUE实战项目的中有一个加载推荐书籍的过渡动画,在项目中是使用JS实现。 当时看视频大概一个小时作用,拆分动画逻辑,写代码更是耗时。后来自己想着能不能用CSS动画直接写出来,折腾了半天,终于算是实现了。 可以查看加载动画地址 /*首先是DOM结构,不能

在VUE实战项目的中有一个加载推荐书籍的过渡动画,在项目中是使用JS实现。


当时看视频大概一个小时作用,拆分动画逻辑,写代码更是耗时。后来自己想着能不能用CSS动画直接写出来,折腾了半天,终于算是实现了。

可以查看加载动画地址
-[-/a>

/*首先是DOM结构,不能像js一样分左右两边,正面翻为反面还要改变z-index,按照同样的布局也尝试过,没有用CSS动画写出来,逻辑太复杂。
这是一个类似翻书一样的动画效果,想着结构分为一页一页,一页旋转180°,完成时再改变“这一页”的z-index。每个page类的before伪类为正面,after伪类为反面;分解5页的在每一秒的动画,写出各自的animation。
*/
<div class="card">
    <div class="page"></div>
    <div class="page"></div>
    <div class="page"></div>
    <div class="page"></div>
    <div class="page"></div>
</div>
 
 
 
        .card{
            width: 50px;
            height: 50px;
            opacity: 0;
            position: relative;
            animation: .5s all;
        }
        .card .page{
            width: 50%;
            height: 100%;
            position: absolute;
            left: 50%;
            top: 0;
            transform-style: preserve-3d;
            transform-origin: left;
        }
        .card .page::before, .card .page::after{
            content: '';
            position: absolute;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            border-radius: 0px 50px 50px 0px;
        }
        .card .page::after{
            border-radius: 50px 0px 0px 50px;
        }
        .card .page:nth-child(1){
            animation: animation1 2s linear infinite;
        }
        .card .page:nth-child(2){
            animation: animation2 2s linear infinite;
        }
        .card .page:nth-child(3){
            animation: animation3 2s linear infinite;
        }
        .card .page:nth-child(4){
            animation: animation4 2s linear infinite;
        }
        .card .page:nth-child(5){
            animation: animation5 2s linear infinite;
        }
        .card .page:nth-child(1)::before{
            background: aqua url("./images/star-right.png") center left/50% 50% no-repeat;
        }
        .card .page:nth-child(1)::after{
            background: hotpink url("./images/compass-left.png") center right/50% 50% no-repeat;
            transform: rotateY(180deg);
        }
        .card .page:nth-child(2)::before{
            background: hotpink url("./images/compass-right.png") center left/50% 50% no-repeat;
        }
        .card .page:nth-child(2)::after{
            background: coral url("./images/crown-left.png") center right/50% 50% no-repeat;
            transform: rotateY(180deg);
        }
        .card .page:nth-child(3)::before{
            background: coral url("./images/crown-right.png") center left/50% 50% no-repeat;
        }
        .card .page:nth-child(3)::after{
            background: cyan url("./images/gift-left.png") center right/50% 50% no-repeat;
            transform: rotateY(180deg);
        }
        .card .page:nth-child(4)::before{
            background: cyan url("./images/gift-right.png") center left/50% 50% no-repeat;
        }
        .card .page:nth-child(4)::after{
            background: yellowgreen url("./images/heart-left.png") center right/50% 50% no-repeat;
            transform: rotateY(180deg);
        }
        .card .page:nth-child(5)::before{
            background: yellowgreen url("./images/heart-right.png") center left/50% 50% no-repeat;
        }
        .card .page:nth-child(5)::after{
            background: aqua url("./images/star-left.png") center right/50% 50% no-repeat;
            transform: rotateY(180deg);
        }
@keyframes animation1 {
            0%{
                z-index: 1;
                transform: rotateY(180deg);
            }
            20%{
                z-index: 1;
                transform: rotateY(180deg);
            }
            40%{
                z-index: 3;
                transform: rotateY(360deg);
            }
            60%{
                z-index: 4;
                transform: rotateY(360deg);
            }
            60.0001%{
                z-index: 4;
                transform: rotateY(0deg);
            }
            80%{
                z-index: 5;
                transform: rotateY(0deg);
            }
            100%{
                z-index: 4;
                transform: rotateY(180deg);
            }
        }
        @keyframes animation2 {
            0%{
                z-index: 5;
                transform: rotateY(0deg);
            }
            20%{
                z-index: 4;
                transform: rotateY(180deg);
            }
            40%{
                z-index: 1;
                transform: rotateY(180deg);
            }
            60%{
                z-index: 3;
                transform: rotateY(360deg);
            }
            80%{
                z-index: 4;
                transform: rotateY(360deg);
            }
            100%{
                z-index: 5;
                transform: rotateY(360deg);
            }
        }
        @keyframes animation3 {
            0%{
                z-index: 4;
                transform: rotateY(0deg);
            }
            20%{
                z-index: 5;
                transform: rotateY(0deg);
            }
            40%{
                z-index: 4;
                transform: rotateY(180deg);
            }
            60%{
                z-index: 1;
                transform: rotateY(180deg);
            }
            80%{
                z-index: 3;
                transform: rotateY(360deg);
            }
            100%{
                z-index: 4;
                transform: rotateY(360deg);
            }
        }
        @keyframes animation4 {
            0%{
                z-index: 3;
                transform: rotateY(0deg);
            }
            20%{
                z-index: 4;
                transform: rotateY(0deg);
            }
            40%{
                z-index: 5;
                transform: rotateY(0deg);
            }
            60%{
                z-index: 4;
                transform: rotateY(180deg);
            }
            80%{
                z-index: 1;
                transform: rotateY(180deg);
            }
            100%{
                z-index: 3;
                transform: rotateY(360deg);
            }
        }
        @keyframes animation5 {
            0%{
                z-index: 2;
                transform: rotateY(0deg);
            }
            20%{
                z-index: 3;
                transform: rotateY(0deg);
            }
            40%{
                z-index: 4;
                transform: rotateY(0deg);
            }
            60%{
                z-index: 5;
                transform: rotateY(0deg);
            }
            80%{
                z-index: 4;
                transform: rotateY(180deg);
            }
            100%{
                z-index: 1;
                transform: rotateY(180deg);
            }
        }

再贴出JS实现:

<div class="flap-card" v-for="(item, index) in flapCardList" :key="index" :style="{zIndex: item.zIndex}">
    <div class="flap-card-circle">
        <div class="flap-card-semi-circle flap-card-semi-circle-left" :style="semiCircleStyle(item, 'left')"
           ref="left"></div>
        <div class="flap-card-semi-circle flap-card-semi-circle-right" :style="semiCircleStyle(item, 'right')"
           ref="right"></div>
    </div>
</div>
data() {
  return {
    front: 0,
    back: 1,
  }
},
methods: {
    // flapCardList是存储着图片信息的对象数组,通过v-for循环和semiCircleStyle方法设置5组图片的背景。
    semiCircleStyle(item, dir) {
        return {
          backgroundColor: `rgb(${item.r}, ${item.g}, ${item.b})`,
          backgroundSize: item.backgroundSize,
          backgroundImage: dir === 'left' ? item.imgLeft : item.imgRight
        }
    },
    rotate(index, type) {
        //卡牌翻转,"front"选择右边卡片,否则选择左边卡片;然后改变dom元素的样式
        const item = this.flapCardList[index]
        let dom
        if (type === 'front') {
          dom = this.$refs.right[index]
        } else {
          dom = this.$refs.left[index]
        }
        dom.style.transform = `rotateY(${item.rotateDegree}deg)`
        dom.style.backgroundColor = `rgb(${item.r}, ${item._g}, ${item.b})`
    },
    flapCardRotate() {
    //首先是翻转函数,每次翻转分正反两面。当动画至90°时,改变背面的z-index值,每一帧动画完毕执行rotate函数以改变样式。
    const frontFlapCard = this.flapCardList[this.front]
    const backFlapCard = this.flapCardList[this.back]
    frontFlapCard.rotateDegree += 10
    frontFlapCard._g -= 5
    backFlapCard.rotateDegree -= 10
    if (backFlapCard.rotateDegree < 90) {
      backFlapCard._g += 5
    }
    if (frontFlapCard.rotateDegree === 90 && backFlapCard.rotateDegree === 90) {
      backFlapCard.zIndex += 2
    }
    this.rotate(this.front, 'front')
    this.rotate(this.back, 'back')
    if (frontFlapCard.rotateDegree === 180 && backFlapCard.rotateDegree === 0) {
      this.next()
    }
  },
  prepare() {
    const backFlapCard = this.flapCardList[this.back]
    backFlapCard.rotateDegree = 180
    backFlapCard._g = backFlapCard.g - 5 * 9
    this.rotate(this.back, 'back')
  },
  next() {
    const frontFlapCard = this.flapCardList[this.front]
    const backFlapCard = this.flapCardList[this.back]
    frontFlapCard.rotateDegree = 0
    backFlapCard.rotateDegree = 0
    frontFlapCard._g = frontFlapCard.g
    backFlapCard._g = backFlapCard.g
    this.rotate(this.front, 'front')
    this.rotate(this.back, 'back')
    this.front++
    this.back++
    const len = this.flapCardList.length
    if (this.front >= len) {
      this.front = 0
    }
    if (this.back >= len) {
      this.back = 0
    }
    // 动态设置zIndex
    // 100 -> 96
    // 99 -> 100
    // 98 -> 99
    // 97 -> 98
    // 96 -> 97
    // (0 - 1 + 5) % 5 = 4
    // (1 - 1 + 5) % 5 = 0
    this.flapCardList.forEach((item, index) => {
      item.zIndex = 100 - ((index - this.front + len) % len)
    })
    this.prepare()
  },
  startFlapCardAnimation() {
    this.prepare()
    this.task = setInterval(() => {
      this.flapCardRotate()
    }, this.intervalTime)
  },
  stopAnimation() {
    //动画停止时,清除所有setTimeout;否则再次进入动画出现错误。
    if (this.task) {
      clearInterval(this.task)
    }
    if (this.timeout) {
      clearTimeout(this.timeout)
    }
    if (this.timeout2) {
      clearTimeout(this.timeout2)
    }
    this.reset()
  },
  runAnimation() {
    //点击推荐,则动画开始(vuex中定义了flapCardVisible,watch监听其变化,为TRUE则动画开始)
    this.runFlapCardAnimation = true
    this.timeout = setTimeout(() => {
      this.startFlapCardAnimation()
      this.startPointAnimation()
    }, 300)
    this.timeout2 = setTimeout(() => {
      this.stopAnimation()
      //2500ms过渡动画结束,推荐图书显示
      this.runBookCardAnimation = true
    }, 2500)
  },
  watch: {
      flapCardVisible(v) {
        if (v) {
          this.runAnimation()
        }
      }
  },
}

写在最后:初次写CSS动画的总结,而且感觉自己的实现并不是很好,应该有更简单些的实现方法。从DOM结构设计,到动画过程分析还欠缺很多。并且一个动画如此费时,在实际项目中应该得不偿失。还是需要大量的练习,经常练手才可熟能生巧。


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://www.jb51.net/css/692095.html
相关文章
  • CSS3浏览器兼容的介绍

    CSS3浏览器兼容的介绍
    一、浏览器兼容 1.1、概要 世界上没有任何一个浏览器是一样的,同样的代码在不一样的浏览器上运行就存在兼容性问题。不同浏览器其内核
  • CSS元素定位之通过元素的标签或者元素的id、cl

    CSS元素定位之通过元素的标签或者元素的id、cl
    大部分人在使用selenium定位元素时,用的是xpath元素定位方式,因为xpath元素定位方式基本能解决定位的需求。xpath元素定位方式更直观,更好
  • 微信小程序纯CSS实现无限弹幕滚动效果

    微信小程序纯CSS实现无限弹幕滚动效果
    啥也不说,先上效果图 实现背景 产品:我们需要一个弹幕滚动效果,类似于微博热搜那种实时评论,但是我们的数据是固定的20条,你让他
  • 使用CSS构建强大且酷炫的粒子动画效果

    使用CSS构建强大且酷炫的粒子动画效果
    粒子动画,顾名思义,就是页面上存在大量的粒子构建而成的动画。传统的粒子动画主要由 Canvas、WebGL 实现。 当然,不使用 HTML + CSS 的主要
  • flex:1的详细介绍

    flex:1的详细介绍
    简单的来说一下在别人问你这个问题的时候怎么来回答它 前端新人,如有错误求大佬指出~求教???? 情景复现 大佬提问:你知道flex: 1;的更深
  • 新的CSS伪类函数 :is 和 :where()示例介绍

    新的CSS伪类函数 :is 和 :where()示例介绍
    在编写 CSS 时,有时可能会使用很长的选择器列表来定位具有相同样式规则的多个元素。例如,如果您想对标题中的 b 标签进行颜色调整,我
  • 纯CSS打字动画的实现方法

    纯CSS打字动画的实现方法
    在一些技术网站中,经常会看到这样一种展示效果:逐个显示一段文本中的字符,模拟出一种打字的效果。通过这种方式可以显著地提升网
  • 实现el-form每行显示两列底部按钮居中效果的教程

    实现el-form每行显示两列底部按钮居中效果的教程
    el-form 每行显示两列,底部按钮居中 问题: 以前的解决办法是:el-col,el-row。但是这里只有一个el-form-item的label数据是已知的,其余项都是循
  • CSS实现六边形的图片效果的代码

    CSS实现六边形的图片效果的代码
    前言 在CodePen上看到一个有意思的效果: 这个效果的难点在于六边形的绘制, 那么接下来我们就一起来看下作者是怎么实现他的吧 实现思路
  • CSS浮动引起的高度塌陷问题的详细介绍

    CSS浮动引起的高度塌陷问题的详细介绍
    正常页面布局 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 style *{ margin:0; padding: 0; } .content{ width:400px; border:1px solid #000; } .box{ width:200px;
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计