MST

星途 面试题库

面试题:Vue 动画性能优化之过渡组动画优化

在 Vue 中使用 `<transition - group>` 渲染列表过渡动画时,可能会遇到性能问题。请分析可能出现性能问题的原因,并提出至少两种有效的优化方法,同时说明每种方法的原理。
18.3万 热度难度
前端开发Vue

知识考点

AI 面试

面试题答案

一键面试

性能问题原因分析

  1. 过渡动画过多:列表项数量较多时,每个列表项都应用过渡动画,会使浏览器需要处理大量动画计算,增加 CPU 和 GPU 负担。
  2. 频繁重排重绘:列表数据变化频繁,触发 <transition - group> 重新渲染,导致页面频繁重排重绘,影响性能。例如删除或添加列表项时,会重新计算元素位置和样式,消耗性能。
  3. 复杂的动画样式:如果过渡动画使用了复杂的 CSS 样式,如滤镜、变换等,会增加浏览器渲染成本,尤其是在列表项较多时,性能问题更明显。

优化方法及原理

  1. 减少过渡动画数量
    • 原理:通过减少应用过渡动画的列表项数量,降低浏览器处理动画计算的负担。例如,只对新添加或删除的列表项应用过渡动画,而不是对所有列表项在数据变化时都应用动画。这样可以显著减少动画计算量,提高性能。
    • 示例代码
<template>
  <div>
    <button @click="addItem">添加</button>
    <transition - group name="list" tag="ul">
      <li v - for="(item, index) in list" :key="item.id" v - if="index === list.length - 1 || index === list.length - 2">
        {{ item.name }}
      </li>
    </transition - group>
  </div>
</template>

<script>
export default {
  data() {
    return {
      list: []
    };
  },
  methods: {
    addItem() {
      this.list.push({ id: Date.now(), name: '新项' });
    }
  }
};
</script>

<style scoped>
.list - enter - active,
.list - leave - active {
  transition: all 0.5s;
}
.list - enter,
.list - leave - to {
  opacity: 0;
  transform: translateX(50px);
}
</style>
  1. 使用 CSS 硬件加速
    • 原理:利用 CSS 的 will-change 属性提前告知浏览器某个元素将会发生变化,让浏览器可以提前优化,并且将动画相关的计算交给 GPU 处理,提高渲染效率。例如,对列表项的过渡动画使用 transform 属性,因为 transform 是可以触发 GPU 加速的属性,相比直接改变 lefttop 等属性,能减少重排重绘。
    • 示例代码
<template>
  <div>
    <transition - group name="list" tag="ul">
      <li v - for="(item, index) in list" :key="item.id">
        {{ item.name }}
      </li>
    </transition - group>
  </div>
</template>

<script>
export default {
  data() {
    return {
      list: []
    };
  },
  methods: {
    addItem() {
      this.list.push({ id: Date.now(), name: '新项' });
    }
  }
};
</script>

<style scoped>
.list - enter - active,
.list - leave - active {
  will - change: transform;
  transition: transform 0.5s;
}
.list - enter,
.list - leave - to {
  transform: translateX(50px);
}
</style>
  1. 使用节流或防抖
    • 原理:当列表数据频繁变化时,使用节流或防抖可以限制 <transition - group> 重新渲染的频率。节流可以在一定时间间隔内只触发一次重新渲染,防抖则是在一定时间内如果再次触发变化,则重新计时,直到计时结束才触发重新渲染。这样可以避免过于频繁的重排重绘,提升性能。
    • 示例代码(防抖)
<template>
  <div>
    <input v - model="inputValue" @input="debounceUpdate">
    <transition - group name="list" tag="ul">
      <li v - for="(item, index) in list" :key="item.id">
        {{ item.name }}
      </li>
    </transition - group>
  </div>
</template>

<script>
import { debounce } from 'lodash';

export default {
  data() {
    return {
      inputValue: '',
      list: []
    };
  },
  methods: {
    updateList() {
      // 根据 inputValue 更新 list
      this.list = this.inputValue.split('').map(char => ({ id: Date.now(), name: char }));
    },
    debounceUpdate: debounce(function() {
      this.updateList();
    }, 300)
  }
};
</script>

<style scoped>
.list - enter - active,
.list - leave - active {
  transition: all 0.5s;
}
.list - enter,
.list - leave - to {
  opacity: 0;
  transform: translateY(50px);
}
</style>