Использование в Svelte

Svelte предоставляет лаконичный синтаксис для работы с реактивными данными и жизненным циклом. Интеграция timeago.js в Svelte минимальна по коду.


Базовый компонент

<!-- TimeAgo.svelte -->
<script>
  import { format } from 'timeago.js';

  export let date;
  export let locale = 'ru';
</script>

<time datetime={date}>{format(date, locale)}</time>

Компонент с автообновлением через onMount

<!-- LiveTimeAgo.svelte -->
<script>
  import { onMount, onDestroy } from 'svelte';
  import { format } from 'timeago.js';

  export let date;
  export let locale = 'ru';

  let label = '';
  let timer;

  onMount(() => {
    label = format(date, locale);
    timer = setInterval(() => {
      label = format(date, locale);
    }, 60000);
  });

  onDestroy(() => {
    clearInterval(timer);
  });
</script>

<time {datetime}>
  {label}
</time>

Компонент с render и cancel

<script>
  import { onMount, onDestroy } from 'svelte';
  import { render, cancel } from 'timeago.js';

  export let date;
  export let locale = 'ru';

  let el;

  onMount(() => render(el, locale));
  onDestroy(() => cancel(el));
</script>

<time bind:this={el} datetime={date} />

Реактивное обновление при смене date

<script>
  import { onMount, onDestroy, afterUpdate } from 'svelte';
  import { render, cancel } from 'timeago.js';

  export let date;
  export let locale = 'ru';

  let el;
  let mounted = false;

  onMount(() => {
    mounted = true;
    render(el, locale);
  });

  afterUpdate(() => {
    if (!mounted || !el) return;
    cancel(el);
    render(el, locale);
  });

  onDestroy(() => cancel(el));
</script>

<time bind:this={el} datetime={date} />

Реактивный label через $:

<script>
  import { onMount, onDestroy } from 'svelte';
  import { format } from 'timeago.js';

  export let date;
  export let locale = 'ru';

  let label = '';
  let timer;

  $: {
    label = format(date, locale);
  }

  onMount(() => {
    timer = setInterval(() => {
      label = format(date, locale);
    }, 60000);
  });

  onDestroy(() => clearInterval(timer));
</script>

<time datetime={date}>{label}</time>

Реактивное выражение $: пересчитывает label при изменении date или locale.


Svelte store для глобальной локали

// stores/locale.js
import { writable } from 'svelte/store';

export const locale = writable('ru');
<script>
  import { format } from 'timeago.js';
  import { locale } from '../stores/locale';

  export let date;

  $: label = format(date, $locale);
</script>

<time datetime={date}>{label}</time>

Svelte action (use:directive)

// actions/timeago.js
import { render, cancel } from 'timeago.js';

export function timeago(node, { locale = 'ru' } = {}) {
  render(node, locale);

  return {
    update({ locale: newLocale }) {
      cancel(node);
      render(node, newLocale);
    },
    destroy() {
      cancel(node);
    },
  };
}

Использование в шаблоне:

<script>
  import { timeago } from '../actions/timeago';
</script>

<time use:timeago={{ locale: 'ru' }} datetime="2025-05-26T10:00:00Z" />

Список с автообновлением

<script>
  import { onMount, onDestroy } from 'svelte';
  import { render, cancel } from 'timeago.js';

  export let posts = [];

  let container;

  onMount(() => {
    const nodes = container.querySelectorAll('time[datetime]');
    render(nodes, 'ru');
  });

  onDestroy(() => cancel());
</script>

<ul bind:this={container}>
  {#each posts as post (post.id)}
    <li>
      <h3>{post.title}</h3>
      <time datetime={post.createdAt} />
    </li>
  {/each}
</ul>

Регистрация локали при инициализации

// src/app.js
import App from './App.svelte';
import { register } from 'timeago.js';
import ru from 'timeago.js/esm/lang/ru';

register('ru', ru);

const app = new App({ target: document.getElementById('app') });
export default app;