酷站(www.ku0.com)-致力于为互联网从业者提供动力!

热门关键词:  企业  as  baidu  c4rp3nt3r  美女
酷站

【云小站】新老客都返现+现金红包+瓜分60万奖池
酷站

css

旗下栏目: html css xml html5 DW bootstrap Frontpage教程

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

来源:互联网搜集 作者:秩名 人气: 发布时间:2019-09-09
本篇文章主要介绍了CSS3实现类似翻书效果的过渡动画的方法,对大家的学习或者工作具有一定的参考学习价值,感兴趣的小伙伴们可以参考一下,也感谢大家对酷站(ku0.com)的支持。

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


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

可以查看加载动画地址


/*首先是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结构设计,到动画过程分析还欠缺很多。并且一个动画如此费时,在实际项目中应该得不偿失。还是需要大量的练习,经常练手才可熟能生巧。

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

相关文章

  • border-radius IE8兼容处理的方法介绍

    border-radius IE8兼容处理的方法介绍

    根据canisue( http://caniuse.com/#search=border-radius ),border-radius兼容性如下图所示: 测试代码: !DOCTYPE htmlhtml head meta charset=UTF-8 meta http-equiv=X-UA-Compatible content=IE=edge,chrome=1 title/title style t......
    02-13
  • css实现3d立体魔方

    css实现3d立体魔方

    今天来做一个简单的3d魔方 先看效果图吧!把这个看会了,一些网上的3d的相册你就都会了 一,html代码 !DOCTYPE htmlhtml lang=zh-CN head title3d立体魔方/title meta charset=UTF-8 /head body div class=top/div !--上 -- div class=bo......
    02-07
  • 详解css实现环形/扇形菜单(基础版)

    详解css实现环形/扇形菜单(基础版)

    项目需要用到环形菜单,初略在网上找了一下,没有找到合适的,于是自己写了一个很简单的,后续再优化。 这个组件是基于react,但是原理都一样。 展开效果如下: 实现 css(less) @centerIconSize: 30px; .flex(@justify: flex-start, @alig......
    01-16
  • 26个常用易忘CSS小技巧介绍

    26个常用易忘CSS小技巧介绍

    收集于平时常用但易忘的CSS实现方法,如有遗漏或补充,还请指正! 解决inline-block元素设置overflow:hidden属性导致相邻行内元素向下偏移 .wrap { display: inline-block; overflow: hidden vertical-align: bottom}.wrap { display: in......
    12-31
  • flex布局中flex-grow与flex-shrink的计算方式解析

    flex布局中flex-grow与flex-shrink的计算方式解析

    CSS 中的 Flex(弹性布局) 可以很灵活的控制网页的布局,其中决定 Flex 布局内项目宽度/高度的是三个属性:flex-basis, flex-grow, flex-shrink. flex-basis flex-basis 决定了项目占据主轴的空间,除非使用 box-sizing 进行设置,否则它......
    12-18
  • better-scroll实现菜单和内容联动的效果

    better-scroll实现菜单和内容联动的效果

    1、基本使用 !DOCTYPE htmlhtml lang=enhead meta charset=UTF-8 meta name=viewport content=width=device-width, initial-scale=1.0 meta http-equiv=X-UA-Compatible content=ie=edge titleDocument/title link href=https://unpkg.co......
    12-09
  • CSS边框长度控制成果的实现

    CSS边框长度控制成果的实现

    以前需要 边框 长度比容器小一些时,我用div嵌套。厥后发明伪类在实现这个效果时很方便,,只需要一个div就够了,另外调解padding和margin都不会很麻烦。 div class=content-blockdiv class=box-containerdiv class=border-topborder top......
    11-29
  • CSS3实现图片抽屉式效果的方法

    CSS3实现图片抽屉式效果的方法

    老规矩,先放图片效果图: 这个效果实现原理很简单:只要你掌握css3动画和过渡相关知识就行,不用js代码; HTML代码: div ul id=list li a href=国际美妆抢先看/a img src=images/1.jpg / /li li a href=女神标准大讨论/a img src=image......
    11-07
  • css :not的多个条件的写法

    css :not的多个条件的写法

    :not 伪类选择器可以筛选不符合表达式的元素 例子 table tbody tr:not(:first-child):not(:last-child) td{ text-align: right;} 以上代码可以选择table表格中tbody部分非首个、非最后一个的tr,并设置其子元素td文本样式居右 这里面需要......
    11-07
  • css的空格处理的方法

    css的空格处理的方法

    1、空格规则 HTML 代码的空格通常会被浏览器忽略。 p hello world /p 上面是一行 HTML 代码,文字的前部、内部和后部各有两个空格。 浏览器的输出结果如下: hello world 可以看到,文字的前部和后部的空格都会忽略,内部的连续空格只会算......
    11-05

最新更新