работать с dom напрямую плохая практика
Не всегда. Зависит от задачи.
Пусть компонент табов принимает в качестве параметров массив значений, описывающих табы и значение, обозначающее активный таб:
props: [ 'items', 'value' ],
В данные компонента положим стили для элемента, изображающего подчёркивание активного таба:
data: () => ({
sliderStyles: null,
}),
Создадим сами табы и элемент подчёркивания:
<ul class="tabs">
<li
v-for="n in items"
:key="n.value"
@click="$emit('input', n.value)"
class="tabs-item"
>{{ n.text }}</li>
</ul>
<div
class="tabs-slider"
:style="sliderStyles"
></div>
Элементу подчёркивания (
.tabs-slider
) зададим абсолютное позиционирование и transition.
Настроим слежение за текущим значением - узнаём его индекс среди доступных для выбора значений, записываем в стили элемента подчёркивания позицию и размер таба с соответствующим индексом:
mounted() {
this.$watch(
'value',
value => {
const index = this.items.findIndex(n => n.value === value);
const el = this.$el.querySelectorAll('.tabs-item')[index];
this.sliderStyles = el
? {
left: `${el.offsetLeft}px`,
width: `${el.offsetWidth}px`,
}
: null;
},
{
immediate: true,
}
);
},
https://jsfiddle.net/vsr5tLue/