Vue3提升性能的习惯

在 Vue 3 中,为了提升性能,可以遵循以下编码习惯和优化策略

1.避免将 v-if 和 v-for 一起使用

当 v-if 和 v-for 一起使用时,每次渲染都会先评估 v-for,然后再进行 v-if 条件判断。这意味着即使 v-if 的条件不满足,v-for 仍然会遍历整个列表,从而造成不必要的性能开销。

解决方案

1.1在 v-for 外部使用 v-if

将 v-if 放在 v-for 的外部,这样可以避免不必要的遍历操作:

<template>
  <div v-if="shouldShowList">
    <div v-for="item in items" :key="item.id">
      {{ item.name }}
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      shouldShowList: true,
      items: [
        { id: 1, name: 'Item 1' },
        { id: 2, name: 'Item 2' }
      ]
    };
  }
};
</script>
1.2使用计算属性过滤数据

使用计算属性提前过滤数据,然后直接在模板中渲染,相当于v-if和v-for逻辑分离

<template>
  <div v-for="item in filteredItems" :key="item.id">
    {{ item.name }}
  </div>
</template>

<script>
export default {
  data() {
    return {
      showActiveItems: true,
      items: [
        { id: 1, name: 'Item 1', active: true },
        { id: 2, name: 'Item 2', active: false }
      ]
    };
  },
  computed: {
    filteredItems() {
      return this.items.filter(item => item.active === this.showActiveItems);
    }
  }
};
</script>
1.3使用 template 包装

如果 v-if 只是用于过滤 v-for 的一些元素,可以使用 template 元素进行包装:

<template>
  <div v-for="item in items" :key="item.id">
    <template v-if="item.shouldShow">
      {{ item.name }}
    </template>
  </div>
</template>

<script>
export default {
  data() {
    return {
      items: [
        { id: 1, name: 'Item 1', shouldShow: true },
        { id: 2, name: 'Item 2', shouldShow: false }
      ]
    };
  }
};
</script>

2.使用 setup 函数

setup 函数是 Vue 3 的 Composition API 的核心部分。它允许你更灵活地组织逻辑,并且在组件实例创建之前执行,从而提升性能。

3.避免不必要的响应式数据

  • 仅为需要响应的数据使用 ref 或 reactive。对于不会改变的数据,使用普通变量。
  • 对于静态内容,可以使用 v-once 指令,这样内容只会渲染一次,并且不会在数据变化时重新渲染。
  • 减少"响应深度",当你只需要对对象的第一层属性进行响应式处理时,使用 shallowRef 和 shallowReactive,可以减少性能开销。
const shallowState = shallowReactive({ foo: 'bar' });

4.避免不必要的计算属性和侦听器

  • 仅在需要时使用计算属性和侦听器,避免它们对性能的负面影响。
  • 合理使用 watch 和 watchEffect,确保仅在必要时进行副作用处理。

5.擅于运用缓存技术

5.1 使用 keep-alive 缓存组件

对于频繁切换的动态组件,可以使用 keep-alive 进行缓存,避免重复创建和销毁组件实例。

<keep-alive>
  <component :is="currentComponent"></component>
</keep-alive>

5.2 使用 v-memo 指令

v-memo 指令允许你缓存包含大量静态内容的渲染输出,仅在指定的依赖项变化时重新渲染。

<p v-memo="[dependency]">This will be cached based on dependency changes.</p>

5.3 teleport移动

在需要将内容移动到指定位置时,使用 teleport 提高性能和可维护性。

<teleport to="#modals">
  <modal-component></modal-component>
</teleport>

6.懒加载

对于不常用的组件,可以使用动态导入和延迟加载来提升初始加载性能。

const LazyComponent = defineAsyncComponent(() => import('./LazyComponent.vue'));

7.节流防抖技术

尽量减少组件的重新渲染次数。对频繁变化的数据,使用节流(throttle)或防抖(debounce)技术来减少更新频率。

import { debounce } from 'lodash';

const handleInput = debounce((value) => {
  // 处理输入
}, 300);

8.优化模板内容

  • 使用事件委托来减少大量相同类型事件的监
  • 减少模板的复杂度和嵌套层次。
  • 使用 CSS 的 display: none 代替 v-if,当你只需要隐藏元素而不是完全移除它时。
  • 合理组织和复用样式,减少样式冲突和冗余。
  • 避免在模板中直接使用内联函数表达式,改为在方法中定义逻辑.
  • 在渲染长列表时,使用 v-for 的 key 属性确保列表元素的唯一性和稳定性。同时,考虑使用虚拟滚动技术(如 vue-virtual-scroller)来优化性能。

虚拟滚动是一种优化长列表渲染的方法,它通过只渲染当前视窗内的元素,大大减少了 DOM 元素的数量,从而提升了性能。虚拟滚动技术在处理大型数据集时尤其有效,因为它避免了同时渲染大量不在视窗中的元素。灵活性较高,支持固定高度和动态高度的列表项,适应多种场景需求

//RecycleScroller
<template>
  <div>
    <RecycleScroller
      :items="items"
      :item-size="50"
      key-field="id"
    >
      <template #default="{ item, index }">
        <div class="item">
          {{ item.name }}
        </div>
      </template>
    </RecycleScroller>
  </div>
</template>

<script>
import { RecycleScroller } from 'vue-virtual-scroller'

export default {
  components: {
    RecycleScroller
  },
  data() {
    return {
      items: Array.from({ length: 10000 }, (_, i) => ({ id: i, name: `Item ${i}` }))
    }
  }
}
</script>

如果列表项的高度(或宽度)不固定,可以使用 DynamicScroller 和 DynamicScrollerItem 组件

// DynamicScroller, DynamicScrollerItem 
<template>
  <div>
    <DynamicScroller
      :items="items"
      key-field="id"
    >
      <template #default="{ item, index }">
        <DynamicScrollerItem :item="item">
          <div :style="{ height: item.height + 'px' }" class="item">
            {{ item.name }}
          </div>
        </DynamicScrollerItem>
      </template>
    </DynamicScroller>
  </div>
</template>

<script>
import { DynamicScroller, DynamicScrollerItem } from 'vue-virtual-scroller'

export default {
  components: {
    DynamicScroller,
    DynamicScrollerItem
  },
  data() {
    return {
      items: Array.from({ length: 10000 }, (_, i) => ({ id: i, name: `Item ${i}`, height: 50 + Math.random() * 100 }))
    }
  }
}
</script>

9.SPA首屏优化

通过减小入口文件、静态资源本地缓存、按需加载 UI 框架、压缩图片资源、避免组件重复打包、开启 GZip 压缩以及使用服务器端渲染,可以显著提升 SPA 应用的首屏加载性能。这些优化策略可以改善用户体验,降低页面加载时间。

  • 减小入口文件积

代码拆分
通过 Webpack、Vite 等构建工具进行代码拆分,将应用的不同部分分离成更小的块,并按需加载。

// 使用动态导入 (Dynamic Imports)
const Home = () => import('./components/Home.vue');

Tree Shaking
确保只打包实际使用的代码,移除未使用的模块和函数

//#配置文件
// 确保构建工具支持 Tree Shaking,如 Webpack 的 mode 设置为 production
module.exports = {
  mode: 'production'
};

2.静态资源本地缓存

配置缓存策略
通过 HTTP 头配置缓存策略,减少不必要的资源请求。

# 在服务器配置中设置缓存头
Cache-Control: public, max-age=31536000

3.UI框架按需加载

按需引入组件,使用按需加载的方式引入 UI 框架中的组件,而不是一次性引入整个库。

// 使用 Babel 插件如 babel-plugin-import
import { Button, Select } from 'ant-design-vue';

4.图片资源的压缩

使用工具(如 ImageMagick、TinyPNG)在部署前压缩图片。
根据使用场景选择最佳的图片格式(如 WebP、JPEG、PNG)。

# 使用 TinyPNG API 压缩图片
tinypng -k YOUR_API_KEY input.png -o output.png
<img src="image.webp" alt="Example Image">

5.组件重复打包

避免组件重复打包
确保组件只被打包一次,可以通过以下方法避免

//方法 1
// 在 Webpack 中配置 alias,确保引用路径一致
module.exports = {
  resolve: {
    alias: {
      '@components': path.resolve(__dirname, 'src/components/')
    }
  }
};
//方法2
//SplitChunksPlugin 配置
const path = require('path');

module.exports = {
  entry: {//entry: 定义了入口文件,app 指向应用程序的入口文件
    app: './src/index.js'
  },
  output: {//output: 定义了输出文件的名称和路径
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  optimization: {//Webpack 4 引入的配置,用于替代Webpack 3 的 CommonsChunkPlugin
    splitChunks: {//用于拆分代码:运行时(指挥)/第三方(外包)/业务app(开发)
      cacheGroups: {
        vendor: {//cacheGroups.vendor: 用于提取第三方库,匹配 node_modules 文件夹中的文件,将它们提取到 vendors 文件中。

          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all'
        },
        common: {//于提取 app 和 vendor 中共享的代码
          name: 'common',
          minChunks: 2,
          chunks: 'all'
        }
      }
    },
    runtimeChunk: {//将 Webpack 运行时代码提取到 runtime 文件中
      name: 'runtime'//指定运行时文件的名称为 runtime.js。
    }
  }
};

6.开启GZip压缩

在 Nginx 配置中启用 GZip

gzip on;
gzip_types text/plain application/javascript text/css;

7.使用SSR
如使用 Nuxt.js(Vue.js)或 Next.js(React)进行服务器端渲染。

// 使用 Nuxt.js 创建一个 SSR 项目
npx create-nuxt-app my-app

知识加油站

事件委托是一种通过利用事件冒泡机制,在父元素上统一处理多个子元素的事件监听的方法。这样可以减少 DOM 上的事件监听器数量,提升性能,特别是在需要处理大量相同类型事件的情况下。

事件冒泡机制

事件冒泡机制是指当一个事件触发时,它会从事件的目标元素开始,一直向上传递到最顶层的祖先元素。这意味着你可以在某个父元素上监听事件,然后统一或者特殊处理所有子元素的事件,而无需在每个子元素上单独添加事件监听器。

动态元素处理:对于动态添加或删除的子元素,无需重新绑定或解绑事件监听器,父元素上的事件监听器仍然有效。

//事件太多 浪费性能
<ul>
  <li @click="handleClick">Item 1</li>
  <li @click="handleClick">Item 2</li>
  <li @click="handleClick">Item 3</li>
</ul>

<script>
export default {
  methods: {
    handleClick(event) {
      console.log(event.target.textContent);
    }
  }
};
</script>
//利用委托 减少事件数量 
<ul @click="handleClick">
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
</ul>

<script>
export default {
  methods: {
    handleClick(event) {
      const target = event.target;
      if (target.tagName === 'LI') {
        console.log(target.textContent);
      }
    }
  }
};
</script>
  • 32
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值