Библиотека Vivus предназначена для анимации SVG-путей через последовательное прорисовывание stroke. В экосистеме Vue.js она используется для создания визуально насыщенных интерфейсов, где SVG становится частью реактивного состояния компонентов.
Ключевой принцип интеграции заключается в том, что Vivus работает
напрямую с DOM-узлами SVG, поэтому взаимодействие с Vue строится через
lifecycle-хуки и ссылки на элементы (ref).
Vivus устанавливается как обычная зависимость:
npm install vivus
Варианты подключения в проекте Vue:
import Vivus from 'vivus'
или через динамический импорт для снижения начального веса:
const Vivus = (await import('vivus')).default
Работа с SVG требует доступа к DOM после монтирования компонента.
<template>
<div class="icon-wrapper">
<svg ref="svgRef" viewBox="0 0 100 100">
<path d="M10 10 H 90 V 90 H 10 Z" />
</svg>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import Vivus from 'vivus'
const svgRef = ref(null)
onMounted(() => {
new Vivus(svgRef.value, {
type: 'delayed',
duration: 120,
animTimingFunction: Vivus.EASE
})
})
</script>
Vivus требует передать DOM-элемент SVG или его id. В Vue
предпочтительно использовать ref, так как он обеспечивает
прямую ссылку на узел после рендера.
Vivus поддерживает несколько стратегий отрисовки SVG:
Пример конфигурации:
new Vivus(svgRef.value, {
type: 'oneByOne',
duration: 200,
start: 'autostart'
})
Каждый режим влияет на восприятие интерфейса: sync
подходит для логотипов, oneByOne — для иллюстраций и
storytelling-интерфейсов.
В архитектуре Vue целесообразно вынести Vivus в переиспользуемый компонент.
<template>
<svg ref="svgRef" :viewBox="viewBox">
<slot />
</svg>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import Vivus from 'vivus'
const props = defineProps({
duration: {
type: Number,
default: 100
},
type: {
type: String,
default: 'delayed'
},
viewBox: {
type: String,
default: '0 0 100 100'
}
})
const svgRef = ref(null)
onMounted(() => {
new Vivus(svgRef.value, {
type: props.type,
duration: props.duration,
start: 'autostart'
})
})
</script>
Такой компонент позволяет абстрагировать логику анимации и повторно использовать её для любых SVG.
Vivus можно контролировать через методы экземпляра:
const vivusInstance = ref(null)
onMounted(() => {
vivusInstance.value = new Vivus(svgRef.value, {
type: 'delayed',
duration: 150,
start: 'manual'
})
})
Дальнейшее управление:
vivusInstance.value.play()
vivusInstance.value.stop()
vivusInstance.value.reset()
В Vue это связывается с реактивными событиями интерфейса:
<button @click="vivusInstance.play()">Запуск</button>
<button @click="vivusInstance.reset()">Сброс</button>
При использовании динамически генерируемых иконок важно учитывать момент, когда DOM полностью сформирован.
<template>
<svg v-if="ready" ref="svgRef">
<path :d="pathData" />
</svg>
</template>
<script setup>
import { ref, watch, nextTick } from 'vue'
import Vivus from 'vivus'
const props = defineProps({
pathData: String
})
const svgRef = ref(null)
const ready = ref(false)
watch(() => props.pathData, async () => {
ready.value = false
await nextTick()
ready.value = true
await nextTick()
new Vivus(svgRef.value, {
type: 'oneByOne',
duration: 120
})
})
</script>
Ключевым моментом является повторная инициализация после обновления DOM.
Для масштабируемых проектов удобно использовать пользовательскую директиву.
export default {
mounted(el, binding) {
new Vivus(el, binding.value || {
type: 'delayed',
duration: 100
})
}
}
Регистрация:
app.directive('vivus', vivusDirective)
Использование:
<svg v-vivus="{ type: 'sync', duration: 80 }">
<path d="..." />
</svg>
При работе с большим количеством SVG-анимаций важно учитывать нагрузку на DOM:
v-once для статических SVGПример:
<svg v-once ref="svgRef">
Также важно избегать повторного создания экземпляров Vivus без уничтожения предыдущих.
Vivus можно сочетать с системой переходов Vue:
<transition name="fade" @after-enter="startAnimation">
<svg v-if="visible" ref="svgRef">
<path d="..." />
</svg>
</transition>
const startAnimation = () => {
new Vivus(svgRef.value, {
type: 'delayed',
duration: 100
})
}
Это позволяет синхронизировать появление компонента и начало отрисовки SVG.
Vivus часто используется для:
В Vue дизайн-система может содержать слой абстракции:
BaseIconAnimated.vueLogoVivus.vueIllustrationStroke.vueКаждый компонент инкапсулирует настройки Vivus и SVG-структуру.
Для повторной анимации требуется сброс состояния:
const replay = () => {
vivusInstance.value.reset()
vivusInstance.value.play()
}
В Vue это связывается с реакцией на изменение маршрута:
watch(() => route.path, () => {
replay()
})
При использовании Nuxt важно учитывать отсутствие DOM на сервере.
if (process.client) {
new Vivus(svgRef.value, options)
}
или:
onMounted(() => {
if (!svgRef.value) return
new Vivus(svgRef.value, options)
})
Это предотвращает ошибки гидратации.
В крупных приложениях логика Vivus выносится в composable:
import Vivus from 'vivus'
import { ref, onMounted } from 'vue'
export function useVivus(options) {
const el = ref(null)
const instance = ref(null)
onMounted(() => {
instance.value = new Vivus(el.value, options)
})
return {
el,
instance
}
}
Использование:
const { el, instance } = useVivus({
type: 'sync',
duration: 120
})
Качество анимации напрямую зависит от структуры SVG:
<path><g> с
трансформациямиПример корректной структуры:
<svg viewBox="0 0 200 200">
<path d="..." />
<path d="..." />
</svg>
Vivus можно связывать с состояниями загрузки:
<svg ref="svgRef" v-if="loading === false">
watch(loading, (val) => {
if (!val) {
new Vivus(svgRef.value, { duration: 100 })
}
})
Это позволяет использовать SVG-анимацию как индикатор завершения процессов.