• 【重点突破】—— Vue2.0 transition 动画Demo实践填坑


    前言:vue1.0版本和2.0版本的过渡系统改变是很大的,具体请详看文档介绍本文转载自郭锦荣的博客,一共列举了四种transition的使用实践,分别是css过渡、css动画、javascript钩子、列表过渡的应用,这里只作为学习梳理。


    css过渡--实践

     

    Demo效果:

    css过滤

    实现思路:通过一个transition来触发多个子元素的过渡效果,我们只需要定义元素对应的过渡效果就可以

                  其他事情vue会帮我们搞定,由此可以扩展出其他酷炫的过渡场景效果。

    代码实现:

    <template>
        <div class="app">
            <button @click="showMenu" class="btn">{{text}}</button>
            <transition name="move">
                <div class="menu" v-show="show">
                    <div class="inner inner-1">1</div>
                    <div class="inner inner-2">2</div>
                    <div class="inner inner-3">3</div>
                </div>
            </transition>
        </div>
    </template>
    
    <script type="text/ecmascript-6">
        export default {
            data () {
                return {
                    show: false
                };
            },
            methods: {
                showMenu () {
                    this.show = !this.show;
                }
            },
            computed: {
                text () {
                    return this.show ? '' : '';
                }
            }
        };
    </script>
    
    <style lang="stylus" rel="stylesheet/stylus">
        .app
            .btn
                position: fixed
                bottom: 50px
                right: 10px
                z-index: 10
                 50px
                height: 50px
                line-height: 50px
                border-radius: 50%
                border: none
                outline: none
                color: #fff
                font-size: 18px
                background: blue
            .menu
                position: fixed
                bottom: 50px
                right: 10px
                 50px
                height: 50px
                border-radius: 50%
                transition: all .7s ease-in
                &.move-enter-active
                    .inner
                        transform: translate3d(0, 0, 0)
                        transition-timing-function: cubic-bezier(0, .57, .44, 1.97)
                    .inner-1
                        transition-delay: .1s
                    .inner-2
                        transition-delay: .2s
                    .inner-3
                        transition-delay: .3s
                &.move-enter, &.move-leave-active
                    .inner
                        transition-timing-function: ease-in-out
                    .inner-1
                        transform: translate3d(0, 60px, 0)
                        transition-delay: .3s
                    .inner-2
                        transform: translate3d(40px, 40px, 0)
                        transition-delay: .2s
                    .inner-3
                        transform: translate3d(60px, 0, 0)
                        transition-delay: .1s
                .inner
                    display: inline-block
                    position: absolute
                     30px
                    height: 30px
                    line-height: 30px
                    border-radius: 50%
                    background: red
                    text-align: center
                    color: #fff
                    transition: all .4s
                .inner-1
                    top: -50px
                    left: 10px
                .inner-2
                    left: -30px
                    top: -30px
                .inner-3
                    left: -50px
                    top: 10px
    </style>

    可以看到我们的代码基本主要是完成css过渡效果的样式,而触发过渡效果只是简单地通过一个click事件就搞定了。

    vue会自动嗅探目标元素是否有 CSS 过渡或动画,并在合适时添加/删除 CSS 类名。

    css 动画--实践

    Demo效果

    css动画

    这个案例的不同之处在于过渡效果是使用css动画来实现。

    <template>
        <div class="app">
        <button @click="showball" class="btn">show</button>
            <transition name="move" type="animation">
                <div class="ball" v-show="show">
                    <div class="inner"></div>
                </div>
            </transition>
        </div>
    </template>
    
    <script type="text/ecmascript-6">
        export default {
            data () {
                return {
                    show: false
                };
            },
            methods: {
                showball () {
                    this.show = !this.show;
                }
            }
        };
    </script>
    
    <style lang="stylus" rel="stylesheet/stylus">
        @keyframes shape-change {
            0%, 100% {
                border-radius: 50%
                background: red
            }
            50% {
                border-radius: 0
                background: blue
            }
        }
        
        @keyframes moveball-in {
            0% {
                transform: translate3d(300px,-200px,0)
            }
            50% {
                transform: translate3d(100px,-400px,0)
            }
            100% {
                transform: translate3d(0,0,0)
            }
        }
        @keyframes moveball-out {
            0% {
                transform: translate3d(0,0,0)
            }
            50% {
                transform: translate3d(100px,-400px,0)
            }
            100% {
                transform: translate3d(300px,-200px,0)
            }
        }
        .app
            .btn
                 40px
                height: 30px
                margin-top: 40px
                border: none
                outline: none
                background: red
                color: #fff
            .ball
                position: absolute
                bottom: 20px
                left: 20px
                 50px
                height: 50px
                transition: all 1s cubic-bezier(.22,-0.86,.97,.58)
                &.move-enter-active
                    opacity: 1
                    animation: moveball-in 1s
                    .inner
                        animation: shape-change 1s
                &.move-leave-active
                    opacity: 0.8
                    animation: moveball-out 1s
                    .inner
                        animation: shape-change 1s
                .inner
                    display: inline-block
                     30px
                    height: 30px
                    border-radius: 50%
                    background: red
                    transition: all 1s linear
    </style>

    实现思路:只需要在vue过渡类名下加了不同的animation

    官网说明:当只使用transition或animation其中一种时,vue是能自动监听对应的类型的,但是如果同一个元素同时使用两种效果,就需要明确指定监听哪一种类型

    其实这个demo已经简单地实现同时使用两种类型的情况,可以看到有一个透明度的变化。

    注意: 假如animation里使用了transform,并且外面也使用了transform的话,那么元素在过渡的时候动画效果就会有冲突,效果就有点出入了。

    JavaScript钩子 -- 实践

    前两个Demo都是有进入和离开的过渡,但是如果一些场景只需要进入过渡然后就结束了,那么这时就可以使用JavaScript钩子结合CSS transitions/animations来实现,当然也可以单独使用。

    Demo效果:

    javascript钩子

    使用场景:这个一个非常low的模拟炮弹发射的场景,可以看到小球有抛物线轨迹运动的过渡,而且发射出去就不会再回来了     

    关键代码:

    <template>
        <div class="app">
            <div class="gun" @click="launch($event)"></div>
            <div class="shells-wrapper">
              <transition v-for="shell in shells" name="launch-shell" @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter">
                <div class="shell" v-show="shell.show">
                  <div class="inner"></div>
                </div>
              </transition>
            </div>
            <div class="goal"></div>
        </div>
    </template>

    误区:由于本身这个案例是一组元素的过渡,所以很容易就会觉得用Vue2.0提供的transition-group不就行了。

    纠正:transition-group是列表过渡,要使用的那一组元素是相关联的、互相影响的

            而这个案例的元素每个都是独立的,只不过是一组独立的元素过渡,所以还是用transition+v-for实现一组相同元素过渡。

    JavaScript钩子实现过渡:

    export default {
            data () {
                return {
                    shells: [
                        {
                            show: false
                        },
                        {
                            show: false
                        },
                        {
                            show: false
                        }
                    ]
                };
            },
            methods: {
                launch (event) {
                    for (let i = 0; i < this.shells.length; i++) {
                      let shell = this.shells[i];
                      if (!shell.show) {
                        shell.show = true;
                        shell.target = event.target;
                        return;
                      }
                    }
                },
                beforeEnter (el) {
                    let count = this.shells.length;
                    while (count--) {
                        let shell = this.shells[count];
                        if (shell.show) {
                            let rect = shell.target.getBoundingClientRect();
                            let left = rect.left - 32;
                            let top = -(window.innerHeight - rect.top - 15);
                            el.style.display = '';
                            el.style.webkitTransform = `translate3d(0,${top}px,0)`;
                            el.style.transform = `translate3d(0,${top}px,0)`;
                            let inner = el.getElementsByClassName('inner')[0];
                            inner.style.webkitTransform = `translate3d(${left}px,0,0)`;
                            inner.style.transform = `translate3d(${left}px,0,0)`;
                        }
                    }
                },
                enter (el, done) {
                    /* eslint-disable no-unused-vars */
                    let refresh = el.offsetHeight;
                    this.$nextTick(() => {
                        el.style.webkitTransform = 'translate3d(0,0,0)';
                        el.style.transform = 'translate3d(0,0,0)';
                        let inner = el.getElementsByClassName('inner')[0];
                        inner.style.webkitTransform = 'translate3d(0,0,0)';
                        inner.style.transform = 'translate3d(0,0,0)';
                    });
                    done();
                },
                afterEnter (el) {
                    let ball = this.shells[0];
                    ball.show = false;
                    el.style.display = 'none';
                }
            }
        };
    • 过渡元素就不需要为其添加vue的过渡css类名了,只需在元素本身添加transition即可,那vue在之前css过渡的时候会自动帮我们去添加对应的类名来完成过渡效果。
    • javascript钩子需要我们自己完成这个始末状态的设置
    • 当我们点击触发一个过渡的时候,在beforeEnter里先拿到当前元素的偏移位置,然后给过渡元素设置其起始位置,在enter里需要重新触发下浏览器的重绘,然后在下一帧重新设置元素的结束位置,这时就会产生过渡效果,在过渡完成后我们将当前元素隐藏即可。
    transition-group -- 实践


    Demo效果:

    transition-group.gif

    使用场景:这个Demo是一个简单的todo lists,当其中一个元素过渡的时候,会影响其他元素的过渡。当然,删除按钮其实本身也是一个transition过渡,也就是说可以在transition-group里使用transition

    关键代码:

    <template>
        <div class="app">
            <button @click="add" class="add-btn">+</button>
            <transition-group name="slide" tag="ul" class="list-wrapper">
                <li class="list" v-for="(item, index) in lists" v-touch:swipeleft="showBtn.bind(this, index)" v-touch:swiperight="hideBtn.bind(this, index)" :key="item">
                    <span class="text">{{item.text}}</span>
                    <transition name="move">
                        <button class="del-btn" @click="delList(index)" v-show="item.show">删除</button>
                    </transition>
                </li>
            </transition-group>
        </div>
    </template>

    坑:之前看官网列表过渡的例子,它是一个数组,元素都是数字,并且每一项都必须设置唯一的key值。

           所以学着在完成demo的时候将索引值index传给key,结果过渡不对,换成对应的item就正常了。

    这个Demo用到了vue-touch,虽然github上说不支持2.0版本了,但是有一个next分支是支持的,只需在项目下安装它即可:

    (sudo) npm install --save git://github.com/vuejs/vue-touch.git#next
    #sudo  mac环境使用

    关键样式:

    .list
        display: flex
         100%
        height: 40px
        line-height: 40px
        margin-bottom: 10px
        color: #666
        font-size: 14px
        background: #eee
        transition: all .4s
        &.slide-move
            transition: transform 1s
        &.slide-enter
            transform: translate3d(-100%, 0, 0)
        &.slide-leave-active
            position: absolute
            transform: translate3d(-100%, 0, 0)
        &:last-child
            margin-bottom: 0
        .del-btn
            flex: 0 0 60px
            border: none
            outline: none
            color: #fff
            background: red
            transition: all .4s
            &.move-enter, &.move-leave-active
                transform: translate3d(70px, 0, 0)
        .text
            flex: 1
            padding-left: 20px

    如果改变定位过渡的duration与进入离开一样的话,其实可以不用-move。这里设置-move的过渡的duration不同于元素进入离开的duration产生一种速度差,看起来舒服点。而且-leave-active需要设置position: absolute才会有效果。现在看来其实列表过渡也是很容易实现的。

  • 相关阅读:
    JDK安装,环境配置
    XSS攻击测试代码
    css3 input边框蓝光特效
    PDFobject插件使用,PDF在线查看插件
    网页中嵌入可以点击“运行代码”执行html/css/js代码
    SmohanTimeLine.js 酷炫的时间轴效果
    java进行文件上传,带进度条
    javascript读取xml文件
    C# 动态类型与动态编译简介
    Mac 命令行美化
  • 原文地址:https://www.cnblogs.com/ljq66/p/9985224.html
Copyright © 2020-2023  润新知