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

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

Используя этот подход, вы можете создавать свои собственные компонуемые объекты Vue. Давай начнем.

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

import { ref, onMounted, onUnmounted, watch, computed } from 'vue';

// state which we define in the `data` function of the component spec
const count = ref(0) 

// all lifecycle methods
onMounted(() => count.value = 0)
onUnmounted(() => count.value = null)

// watchers
watch(count, (newVal) => fetch())

// computed properties
const countToString = computed(() => count.value.toString());

Используя эти нативные хуки, мы можем создавать собственные компонуемые хуки.

Чтобы создать наш useDocumentVisible, мы присоединим прослушиватель событий к событию visibilityChange на document, который вызывает наш обработчик всякий раз, когда изменяется видимость. Для этого мы будем использовать компонуемые хуки жизненного цикла.

import { onMounted, onUnmounted } from 'vue';

function useDocumentVisible() {
  function handler() {};

  onMounted(() => document.addEventListener('visibilitychange', handler));
  onUnmounted(() => document.removeEventListener('visibilitychange', handler));
}

Отлично, так как наш handler на месте, он будет срабатывать каждый раз, когда мы переключаем вкладки или окна. Давайте добавим реактивное свойство для отслеживания текущего visibilityState из document .

import { onMounted, onUnmounted, ref } from 'vue';

function useDocumentVisible() {
  const documentVisibility = ref(document.visibilityState === "visible");
  
  function handler() {};

  onMounted(() => document.addEventListener('visibilitychange', handler));
  onUnmounted(() => document.removeEventListener('visibilitychange', handler));
}

Мы можем проверить, виден документ или нет, используя visibilityState объекта document. Он может иметь только два значения visible или hidden.

Реактивная утилита ref ожидает начальное значение, мы устанавливаем его в зависимости от того, установлено ли текущее visibilityState в visible .

Поскольку наше реактивное свойство на месте, теперь нам просто нужно добавить логику для его изменения, когда обработчик вызывается при переключении вкладок/окон, что должно войти в функцию handler.

import { onMounted, onUnmounted, ref } from 'vue';

function isDocumentVisible() {
  return document.visibilityState === "visible";
}

function useDocumentVisible() {
  const documentVisibility = ref(isDocumentVisible());

  function handler() {
    documentVisibility.value = isDocumentVisible();
  }

  onMounted(() => {
    document.addEventListener('visibilitychange', handler);
  });

  onUnmounted(() => {
    document.removeEventListener('visibilitychange', handler);
  });
}

Чтобы обновить значение любого свойства, созданного с помощью утилиты ref, мы делаем это, обновляя ключ property.value этого свойства. Хотя мы должны сделать это, чтобы обновить значение свойства, Vue автоматически разворачивает его во время рендеринга.

Кроме того, мы преобразовали логическую логику, которая проверяет, установлен ли текущий visibilityState в visible, в отдельную функцию isDocumentVisible.

Наконец, мы вернем свойство documentVisibility из этого компонуемого хука для использования в приложении.

import { onMounted, onUnmounted, ref } from 'vue';

function isDocumentVisible() {
  return document.visibilityState === "visible";
}

function useDocumentVisible() {
  const documentVisibility = ref(isDocumentVisible());

  function handler() {
    documentVisibility.value = isDocumentVisible();
  }

  onMounted(() => {
    document.addEventListener('visibilitychange', handler);
  });

  onUnmounted(() => {
    document.removeEventListener('visibilitychange', handler);
  });

  return documentVisibility;
}

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



Выше находится предварительный просмотр демоверсии в реальном времени. Давайте посмотрим на код приложения ниже.

<template>
  <div id="app"></div>
</template>

<script>
import { watch } from 'vue';
import { useDocumentVisible } from './useDocumentVisible';

export default {
  name: 'App',
  setup() {
    const isDocumentVisible = useDocumentVisible();

    const audio = new Audio(
      'https://filesamples.com/samples/audio/mp3/sample3.mp3'
    );

    watch(
      isDocumentVisible,
      (isDocumentVisible) => {
        if (isDocumentVisible) audio.play();
        else audio.pause();
      },
      { immediate: true }
    );
  },
};
</script>

Здесь мы используем наш хук useDocumentVisible, чтобы получить реактивное свойство независимо от того, виден документ или нет, и мы начинаем наблюдать за ним, используя составной хук watch, в обработчике мы просто вызываем play, когда свойство true, и pause, когда оно false.

Обратите внимание, что мы также использовали immediate как true для запуска watch при начальной загрузке.

Так легко! Вы можете использовать эти компонуемые обработчики API для создания собственных составных обработчиков.

Я буду писать больше статей о Vue Composables, так что следите за обновлениями и следите за новостями.