Использование в Vue.js

Vue.js предоставляет несколько механизмов для интеграции с timeago.js: composables (Vue 3), директивы, компоненты. Выбор зависит от требуемого уровня инкапсуляции.


Установка и регистрация локали

// src/main.js (Vue 3)
import { createApp } from 'vue';
import App from './App.vue';
import { register } from 'timeago.js';
import ru from 'timeago.js/esm/lang/ru';

register('ru', ru);

createApp(App).mount('#app');

Простое использование format в шаблоне

<script setup>
import { format } from 'timeago.js';

const props = defineProps({ date: String });
</script>

<template>
  <time :datetime="date">{{ format(date, 'ru') }}</time>
</template>

Composable useTimeAgo

// composables/useTimeAgo.js
import { ref, watchEffect, onUnmounted } from 'vue';
import { format } from 'timeago.js';

export function useTimeAgo(date, locale = 'ru') {
  const label = ref(format(date, locale));

  const id = setInterval(() => {
    label.value = format(date, locale);
  }, 60000);

  onUnmounted(() => clearInterval(id));

  return label;
}

Использование в компоненте:

<script setup>
import { useTimeAgo } from '@/composables/useTimeAgo';

const props = defineProps({ date: String });
const label = useTimeAgo(props.date, 'ru');
</script>

<template>
  <time :datetime="props.date">{{ label }}</time>
</template>

Composable с адаптивным интервалом

// composables/useAdaptiveTimeAgo.js
import { ref, onUnmounted } from 'vue';
import { format } from 'timeago.js';

function getInterval(date) {
  const diff = Math.abs(Date.now() - new Date(date).getTime());
  if (diff < 60000)    return 10000;
  if (diff < 3600000)  return 60000;
  if (diff < 86400000) return 1800000;
  return 86400000;
}

export function useAdaptiveTimeAgo(date, locale = 'ru') {
  const label = ref(format(date, locale));
  let timer;

  function tick() {
    label.value = format(date, locale);
    timer = setTimeout(tick, getInterval(date));
  }

  timer = setTimeout(tick, getInterval(date));
  onUnmounted(() => clearTimeout(timer));

  return label;
}

Компонент TimeAgo

<!-- components/TimeAgo.vue -->
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { render, cancel } from 'timeago.js';

const props = defineProps({
  date:   { type: String, required: true },
  locale: { type: String, default: 'ru' },
});

const el = ref(null);

onMounted(() => {
  if (el.value) render(el.value, props.locale);
});

onBeforeUnmount(() => {
  if (el.value) cancel(el.value);
});
</script>

<template>
  <time ref="el" :datetime="date" />
</template>

Reactive locale

<script setup>
import { ref, watch } from 'vue';
import { format } from 'timeago.js';

const props = defineProps({ date: String });
const locale = inject('locale', ref('ru'));

const label = ref('');

function update() {
  label.value = format(props.date, locale.value);
}

update();
watch([() => props.date, locale], update);
</script>

<template>
  <time :datetime="props.date">{{ label }}</time>
</template>

Computed property для форматирования

<script setup>
import { computed } from 'vue';
import { format } from 'timeago.js';

const props = defineProps({ date: String });

const label = computed(() => format(props.date, 'ru'));
</script>

<template>
  <time :datetime="props.date">{{ label }}</time>
</template>

computed пересчитывается только при изменении props.date, но не обновляется со временем. Подходит для статичных списков.


Vue 3 + Pinia

Интеграция с locale из Pinia store:

// stores/locale.js
import { defineStore } from 'pinia';

export const useLocaleStore = defineStore('locale', {
  state: () => ({ current: 'ru' }),
  actions: {
    setLocale(locale) {
      this.current = locale;
    }
  }
});
<script setup>
import { computed } from 'vue';
import { format } from 'timeago.js';
import { useLocaleStore } from '@/stores/locale';

const props = defineProps({ date: String });
const store = useLocaleStore();

const label = computed(() => format(props.date, store.current));
</script>

Vue 2 (Options API)

<template>
  <time :datetime="date">{{ label }}</time>
</template>

<script>
import { format } from 'timeago.js';

export default {
  props: {
    date: String,
  },
  data() {
    return { label: '' };
  },
  created() {
    this.label = format(this.date, 'ru');
    this.timer = setInterval(() => {
      this.label = format(this.date, 'ru');
    }, 60000);
  },
  beforeDestroy() {
    clearInterval(this.timer);
  },
};
</script>