Оптимизация производительности приложений Vue.js — забота каждого фронтенд-разработчика.

В этой статье я поделюсь 10 советами по оптимизации Vue.js, которые вам нужно знать начинающему или опытному пользователю интерфейса. Я надеюсь, что эти советы помогут вам, изучаете ли вы Vue.js или уже используете его в разработке приложений.

1. Установите key в v-for

🔗 Ссылка на документ: https://vuejs.org/api/built-in-directives.html#v-for

Использование key в v-for очень важно, поскольку позволяет Vue лучше отслеживать состояние и позицию каждого элемента.

Когда порядок элементов изменяется, отсутствие key приводит к снижению производительности, поскольку Vue необходимо повторно сгенерировать элементы. Чтобы корректно установить key, вы можете извлечь уникальный атрибут из данных в качестве значения ключа. Вот пример кода:

<template v-for="(item, index) in items" :key="item.id">
  <div>{{ item.title }}</div>
</template>

Если нет такого уникального свойства, как item.id, рассмотрите возможность использования index в качестве значения key.

Обратите внимание, что вы не должны использовать index в качестве значения key, когда вам нужно добавить или удалить данные, так как это может вызвать исключения для данных страницы.

2. Правильно используйте v-if и v-show

🔗 Ссылка на документ: https://vuejs.org/guide/essentials/conditional.html#v-if-vs-v-show

И v-if, и v-show могут управлять отображением и скрытием элементов, но они используются в разных сценариях.

  • v-if подходит для сценариев, где требуется частое переключение, когда прослушиватели событий и дочерние компоненты внутри компонента уничтожаются и перестраиваются;
  • v-show используется в сценариях, где не требуется частое переключение, и отображается независимо от начальных условий, за исключением того, что свойство CSS display управляющего элемента определяет, отображается он или нет;

В целом, v-if имеет более высокие накладные расходы на переключение, а v-show имеет более высокие начальные накладные расходы на рендеринг. Поэтому, если требуется частое переключение, предпочтительнее v-show; если условия привязки редко меняются во время выполнения, более подходящим является v-if. Вот пример кода:

<!-- Use v-if -->
<template v-if="show">
  <div>{{ message }}</div>
</template>

<!-- Use v-show -->
<template>
  <div v-show="show">{{ message }}</div>
</template>

3. Используйте KeepAlive для кэширования состояния компонента по мере необходимости.

🔗 Ссылка на документ: https://vuejs.org/guide/built-ins/keep-alive.html#keepalive

KeepAlive — это встроенный компонент, который кэширует состояние компонентов, чтобы избежать дублирования рендеринга и повысить скорость отклика страницы. Кэширует удаленные экземпляры компонентов при динамическом переключении между несколькими компонентами.

Однако, если KeepAlive используется неправильно, это может привести к утечке памяти и другим проблемам. Поэтому при использовании KeepAlive нужно знать сценарии его использования и своевременно уничтожать кешированные компоненты. Вот пример кода:

<template>
  <keep-alive>
    <router-view v-if="$route.meta.keepAlive"></router-view>
  </keep-alive>
</template>

Кроме того, KeepAlive также поддерживает настройку maximum number of cached instances для ограничения максимального количества экземпляров компонентов, которые можно кэшировать. Если количество кэшированных экземпляров вот-вот превысит указанное максимальное число, кэшированные экземпляры, к которым не было доступа в течение длительного времени, будут уничтожены, чтобы освободить место для новых экземпляров.

Вот пример кода:

<KeepAlive :max="10">
  <component :is="activeComponent" />
</KeepAlive>

4. Своевременное уничтожение событий

🔗 Ссылка на документ: https://vuejs.org/api/composition-api-lifecycle.html#onbeforeunmount

Компоненты, использующие прослушиватели событий, таймеры и асинхронные операции, необходимо вовремя уничтожать, чтобы предотвратить утечку памяти.

В Vue3 предусмотрена функция setup, и вы можете использовать хук onBeforeUnmount для уничтожения событий и других ресурсов. Вот пример кода:

import { onBeforeUnmount } from "vue";
export default {
  setup() {
    let timer;
    const startTimer = () => {
      timer = setInterval(() => {
        console.log("timer is running");
      }, 1000);
    };
    const stopTimer = () => {
      clearInterval(timer);
    };
    onBeforeUnmount(() => {
      stopTimer();
    });
    return {
      startTimer,
      stopTimer,
    };
  },
};

5. Обратите внимание на оптимизацию объема

Vue3 относительно большой и нуждается в оптимизации по размеру. Этого можно добиться, настроив инструмент упаковки так, чтобы он упаковывал только необходимые модули, добавляя сторонние библиотеки по запросу и т. д.

В качестве альтернативы вы можете использовать инструменты оптимизации на основе Tree Shaking, такие как PurgeCSS, Babel Minify и UglifyJS, для дальнейшего сжатия кода. Вот пример кода:

// vue.config.js
module.exports = {
  configureWebpack: {
    optimization: {
      splitChunks: {
        chunks: "all",
        minSize: 20000,
        maxSize: 0,
        minChunks: 1,
        maxAsyncRequests: 30,
        maxInitialRequests: 30,
        automaticNameDelimiter: "~",
        cacheGroups: {
          vendors: {
            test: /[\\/]node_modules[\\/]/,
            priority: -10,
          },
          default: {
            minChunks: 2,
            priority: -20,
            reuseExistingChunk: true,
          },
        },
      },
    },
  },
};

6. Использование EventBus для разделения бизнеса

EventBus обеспечивает связь между компонентами и отделяет их друг от друга. Вы также можете использовать инструменты глобального управления состоянием, такие как Vuex, для достижения этой цели.

При использовании EventBus необходимо обращать внимание на присвоение имен событиям и стараться избегать прослушивания одного и того же события несколькими компонентами. Вот пример кода:

// event-bus.js
import mitt from "mitt";
export const eventBus = mitt();
// component.js
export default {
  mounted() {
    eventBus.on("foo", this.handleFoo);
  },
  methods: {
    handleFoo() {
      // do something
    },
  },
  beforeUnmount() {
    eventBus.off("foo", this.handleFoo);
  },
};
// other-component.js
export default {
  mouted() {
    eventBus.emit("foo");
  },
};

7. Использование динамических компонентов для решения проблемы перегрузки if-else

Когда логика if-else слишком сложна, для ее реализации можно использовать динамические компоненты, чтобы избежать раздувания кода и ухудшения читабельности. Использование динамических компонентов может сделать код более четко организованным, повторно использовать компоненты и избежать избыточности кода. Вот пример кода:

<template>
  <component :is="componentName"></component>
</template>
<script>
import Foo from "./Foo.vue";
import Bar from "./Bar.vue";
export default {
  data() {
    return {
      componentName: "",
    };
  },
  mounted() {
    if (condition) {
      this.componentName = "Foo";
    } else {
      this.componentName = "Bar";
    }
  },
  components: {
    Foo,
    Bar,
  },
};
</script>

8. Отложенная загрузка с асинхронными компонентами

🔗 Ссылка на документ: https://vuejs.org/guide/components/async.html#async-components

Асинхронные компоненты обеспечивают отложенную загрузку, сокращение времени загрузки компонентов и повышение скорости отклика страницы. Vue3 изначально поддерживает асинхронную загрузку компонентов, чего можно добиться с помощью синтаксиса import(). Примеры кода следующие:

import { defineAsyncComponent } from "vue";
const AsyncComp = defineAsyncComponent(() => import("./Foo.vue"));

9. Сокращение вычислений с использованием computed и watch

🔗 Ссылка на документ: https://vuejs.org/api/reactivity-core.html

Использование computed и watch может уменьшить избыточную визуализацию или повторяющиеся вычисления.

computed может кэшировать результаты вычислений, чтобы при изменении ответных данных заново вычислялись только зависимые данные. watch может прослушивать изменения в одном или нескольких реагирующих источниках данных и выполнять соответствующие действия, чтобы избежать ручного прослушивания изменений данных.

Ниже приведен пример кода:

<template>
  <div>{{ fullName }}</div>
</template>
<script>
export default {
  data() {
    return {
      firstName: "John",
      lastName: "Doe",
    };
  },
  computed: {
    fullName() {
      return this.firstName + " " + this.lastName;
    },
  },
  watch: {
    firstName(newValue, oldValue) {
      console.log("firstName", newValue, oldValue);
    },
    lastName(newValue, oldValue) {
      console.log("lastName", newValue, oldValue);
    },
  },
};
</script>

10. Оптимизация слотов прицела с помощью v-slot

🔗 Ссылка на документ: https://vuejs.org/api/built-in-directives.html#v-slot

Слот области (также известный как именованный слот) может передавать данные от родительского компонента к дочернему компоненту и отображать дочерний компонент. Однако, когда в слотах области видимости слишком много контента, это может затруднить сопровождение кода. Следовательно, синтаксис v-slot (называемый slot-scope в Vue2) можно использовать для оптимизации слотов области действия.

v-slot позволяет определить имя слота области действия в шаблоне, что делает код более явным и легким для чтения. Ниже приведен пример кода:

<!-- In Vue 3 -->
<template>
  <my-component>
    <template v-slot:title="{ name }"> {{ name }}'s Title </template>
  </my-component>
</template>

<!-- In Vue 2 -->
<my-component>
  <template slot-scope="{ name }"> {{ name }}'s Title </template>
</my-component>

Используя v-slot, мы можем указать имя и содержимое слотов областей в шаблоне и избежать путаницы компонентов.

Краткое содержание

Мы надеемся, что 10 советов по оптимизации, представленных в этой статье, помогут читателям лучше понять Vue.js и создавать более эффективные и надежные веб-приложения.