关于vue的transition中的几个钩子函数为什么没有产生动画

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./js/vue.js"></script>
</head>
<body>
    <div id="test">
      <button @click="show = !show">
        Toggle
      </button>
      <transition
        v-on:before-enter="beforeEnter"
        v-on:enter="enter"
        v-on:after-enter="afterEnter"
        v-on:leave="leave"
      >
        <div v-show="show" ref="oDiv" style="width:200px;height:200px">
          Demo
        </div>
      </transition>
    </div>

    <script>
        new Vue({
          el: '#test',
          data: {
            show: false
          },
          methods: {
            beforeEnter(el) {
                el.style.opacity = 0.6
                el.style.transformOrigin = 'left'
                el.style.transform = 'translate3d(2px, 4px, 0) scale(4)'
            },
            enter(el, done) {
                this.$refs.oDiv.style.background = 'red'
                this.$nextTick(() => {
                    el.style.opacity = 1
                    el.style.transition  = 'all 10.4s'
                    el.style.transform = 'translate3d(0, 0, 0) scale(1)'
                })
                el.addEventListener('transitionend', done)
            },
            afterEnter(el) {
                this.$refs.oDiv.style.transition  = ''
            },
            leave(el, done) {
                // 这句如果加的话就有动画了
                // this.$refs.oDiv.style.width = '200px'
            }
    </script>
</body>
</html>

比如这样,我的理解是beforeEnter相当于过渡类名中的v-enter,enter相当于v-enter-active, 结果却没有动画效果,请问这是什么原因,谢谢!


下面是写在app的子组件,不加任何el.clientHeight或者offsetHeight,只是加了this.$nextTick()异步执行,然后就有动画了,更奇怪的是我在leave钩子里都没写异步,就像上文那样写还是有过渡leave效果

<div ref="test" style="width:200px;height:200px;background:red"></div>

beforeEnter(el) {
  this.$refs.test.style.transform = 'translate3d(2px, 3px, 0) scale(0.1)'
  this.$refs.test.test.style.opacity = 0
},
enter(el, done) {
  this.$nextTick(() => {
    this.$refs.test.style.transition = 'all 10.4s'
    this.$refs.test.style.transform = 'translate3d(0, 0, 0) scale(1)'
    this.$refs.test.test.style.opacity = 1
  })
  this.$refs.test.addEventListener('transitionend', done)
},
afterEnter() {
  this.$nextTick(() => {
    this.$refs.test.style.transition = ''
  })
},
leave(el, done) {
  this.$refs.test.style.transition = 'all 0.4s'
  this.$refs.test.style[transform] = 'translate3d(2px, 5px, 0) scale(4)'
  this.$refs.test.addEventListener('transitionend', done)
}

回答:

我们改写为原生的js整个执行机制应该类似于这样

// css

#el{
  width:200px;
  height:200px;
  background:red;
  display:none;
}

// html

<div id="test">
  <button onclick="begin()">
    Toggle
  </button>
  <div id="el">
    Demo
  </div>
</div>

// js

var el = document.querySelector('#el')
function begin () {
  el.style.display = 'block'
  // console.log(el.offsetWidth) 注意注释掉的这一行
  beforeEnter()
  enter()
}
function beforeEnter() {
  el.style.opacity = 0.6
  el.style.transformOrigin = 'left'
  el.style.transform = 'translate3d(2px, 4px, 0) scale(4)'
}
function enter(done) {
  el.style.transition = 'all 1s'
  el.style.opacity = 0.6
  el.style.opacity = 1
  el.style.transform = 'translate3d(10px, 0, 0) scale(1)'
}
  • 你会发现过渡效果也是没有生效的。
  • 原因在于浏览器不会根据你js对style的修改实时更新,而一般是在当前js修改完毕之后,会对所有修改统一更新,而display:none(它本身是不能transition的)的状态切换影响了其他过渡效果的切换,毕竟为none的元素没法触发过渡。
  • 将offsetWidth打开,你会发现过渡生效了,原因在于取offsetWidth导致浏览器重绘,使后面的style修改前,display确确实实变为了block,从而消除了元素状态为none对过渡的这种影响。添加setTimeout,“打断”js的执行也可生效。

暂无评论

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注