1. vue3+TransitionGroup+ref下的bug

142 阅读1分钟

有如下代码,使用input时,可以正常动画,但使用<input ref="inputRef" /> 时,动画效果就会出现意外,解释原因和提供解决方案

<template>
  <TransitionGroup name="container" tag="ul" class="container" key="counts">
    <div  v-for="(_, index) in counts"  :key="index">
      <!-- container-leave-active container-move container-leave-to -->
      <!-- container-leave-active container-leave-to -->
      <!-- animation when leave doesn't work -->
      <!-- <input ref="inputRef" /> -->
      <!-- animation when leave works -->
      <input />
      <button @click="remove(index)"  >delete</button>
    </div>
    <button @click="add" >add input</button>
  </TransitionGroup>
</template>

<script>
import { ref } from 'vue'

export default {
  name: 'App',
  setup(){
    const counts = ref([1,2,3,4,5]);
    const inputRef = ref();
    const add = () => {
      counts.value.push(counts.value[counts.value.length - 1] + 1);
    };

    const remove = (index) => {
      counts.value.splice(index, 1);
    };

    return {
      inputRef,
      remove,
      add,
      counts
    }
  }
}
</script>

<style>
.container {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 1rem;
  row-gap: 2rem;
  background: #add8e620;
}

.container-move,
.container-enter-active,
.container-leave-active {
  transition: all 0.3s ease-in-out;
}

.container-enter-from,
.container-leave-to {
  opacity: 0;
  transform: translateX(50px);
}

.container-leave-active {
  position: absolute ;
}
</style>

解决方案

并不了解具体的业务,和使用ref获取dom的场景,这里只提解决

加上序号处理

<input :ref="index+'inputRef'" /> 

在js中,动态的获取即可

 const { proxy } = getCurrentInstance();
 proxy.$refs

proxy.$refs并不是一个响应式的数据,他的内容修改后,不会全局刷新

使用父级容器,使用时,根据index处理

<TransitionGroup name="container" tag="ul" class="container" key="counts" ref="inputRef">
inputRef.querySelector("div:nth-of-type(5) button")

同样,不会产生一次渲染

原因

ref 获取dom节点的实现原理,当页面渲染后,会重新计算$refs对应的dom节点数量,此时,相当于执行了如下操作

inputRef.value = [...]

这种操作会引起第二次渲染,而第二次渲染,会对动画效果的计算产生影响,即bug