You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue项目API大量数据获取与v-for渲染卡顿优化咨询

Vue列表渲染卡顿优化方案

一、优化数据获取逻辑,减少响应式更新次数

原代码在遍历API返回数据时,每次都通过数组展开重新赋值,导致几百条数据触发几百次Vue响应式更新,直接阻塞主线程。

优化方案:先在内存中构建完整数组,再一次性赋值给响应式变量,只触发两次更新:

async created() {
  this.loaded = false;
  try {
    const response = await fetch('https://api2.binance.com/api/v3/ticker/24hr');
    const data = await response.json();
    // 内存中预构建数组
    const symbols = [];
    const prices = [];
    data.forEach(element => {
      symbols.push(element.symbol);
      prices.push(+element.lastPrice);
    });
    // 一次性赋值,减少响应式触发次数
    this.chartData.symbols = symbols;
    this.chartData.price = prices;
    this.loaded = true;
  } catch (e) {
    console.error(e);
  }
},

二、给大数据列表添加虚拟滚动

Binance API返回几百条交易对,直接渲染全部DOM会导致节点数量暴增,搜索和滚动时卡顿。使用Vuetify的v-virtual-scroll只渲染可视区域节点。

优化方案:

  1. 替换原列表容器为虚拟滚动组件:
<!-- 替换原v-row -->
<v-virtual-scroll
  :items="filteredPairs"
  height="600px"
>
  <template v-slot="{ item: pair, index }">
    <v-list-item :key="pair.symbol">
      <v-list-item-content>
        <v-list-item-title>{{ pair.symbol }} - {{ pair.price }}</v-list-item-title>
      </v-list-item-content>
      <v-text-field
        outlined
        v-model="numberValue"
        hide-details
        single-line
        type="number"
        class="shrink mr-2"
        width="50px"
        height="50px"
      />
      <AddBtn @click-event="searchHandle(index)" />
    </v-list-item>
  </template>
</v-virtual-scroll>
  1. 将搜索过滤逻辑改为computed缓存结果:
computed: {
  pairs() {
    return this.chartData.symbols.map((symbol, i) => ({
      symbol,
      price: this.chartData.price[i]
    }));
  },
  filteredPairs() {
    if (!this.search.trim()) return this.pairs;
    const keyword = this.search.toLowerCase();
    return this.pairs.filter(pair => 
      pair.symbol.toLowerCase().includes(keyword)
    );
  }
},

三、避免不必要的DOM操作和响应式更新

  1. 移除冗余的DOM引用:原代码用ref="refWord"获取文本内容,易出错且增加DOM开销,直接通过过滤后的数组取数:
searchHandle(index) {
  const pair = this.filteredPairs[index];
  this.chartData.labels = [...this.chartData.labels, pair.symbol];
  this.chartData.datasets[0].data = [
    ...this.chartData.datasets[0].data,
    pair.price
  ];
},
  1. 修正key的错误用法:主页面列表用index++作为key会导致Vue无法正确复用DOM,改用唯一标识:
<v-list-item
  class="border"
  v-for="(label, index) in chartData.labels"
  :key="label"
>

四、优化PieChart组件渲染逻辑

原组件未监听props变化,数据更新后图表无法正确刷新,且易触发重复渲染。

优化方案:添加watch监听props变化,动态更新图表数据:

export default {
  name: 'PieChart',
  components: {Pie},
  props: ['data', 'bgColor', 'labels'],
  data() {
    return {
      chartData: {
        labels: [...this.labels],
        datasets: [
          {
            data: [...this.data],
            backgroundColor: [...this.bgColor],
          },
        ],
      },
      emptyChartData: {
        labels: [],
        datasets: [
          {
            data: [0.01],
            backgroundColor: ['#999797'],
          },
        ],
      },
      chartOptions: {
        responsive: true,
        elements: {
          arc: {
            borderWidth: 0,
          },
        },
      },
      loaded: true,
    };
  },
  watch: {
    labels: {
      handler(newVal) {
        this.chartData.labels = [...newVal];
      },
      deep: true
    },
    data: {
      handler(newVal) {
        this.chartData.datasets[0].data = [...newVal];
      },
      deep: true
    },
    bgColor: {
      handler(newVal) {
        this.chartData.datasets[0].backgroundColor = [...newVal];
      },
      deep: true
    }
  }
};

同时移除父组件中PieChart的:key="this.chartData.labels.length",避免组件频繁重建。

五、其他细节优化

  • 替换页面刷新逻辑:原location.reload()会导致全页重载,改为重新获取数据:
refreshPage() {
  this.chartData.symbols = [];
  this.chartData.price = [];
  this.created();
},
  • 搜索输入防抖:用防抖函数减少搜索过滤的触发频率,避免输入时频繁计算:
import _ from 'lodash';

export default {
  created() {
    this.debouncedFilter = _.debounce((keyword) => {
      this.filterKeyword = keyword;
    }, 300);
  },
  watch: {
    search(val) {
      this.debouncedFilter(val);
    }
  },
  computed: {
    filteredPairs() {
      if (!this.filterKeyword?.trim()) return this.pairs;
      const keyword = this.filterKeyword.toLowerCase();
      return this.pairs.filter(pair => 
        pair.symbol.toLowerCase().includes(keyword)
      );
    }
  }
}

内容的提问来源于stack exchange,提问作者theplaceofburak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 13:20:27