Vue 3 Composition API - Как получить компонентный элемент ($ el), на котором установлен компонент
Я хочу использовать onMounted
для запуска сторонней библиотеки. Для этого мне нужен компонентный элемент в качестве контекста. В Vue 2 я бы получил это сthis.$el
но не знаю, как это сделать с помощью функций композиции. setup
имеет два аргумента, и ни один из них не содержит элемента.
setup(props, context) {
onMounted(() => {
interact($el)
.resizable();
})
}
4 ответа
tl;dr:
В Vue 3 компоненты больше не ограничены только одним корневым элементом. Неявно это означает, что у вас больше нет$el
.
Вы должны использоватьref
для взаимодействия с любым элементом вашего шаблона.
Как указано в комментариях @AndrewSee, при использовании функции рендеринга (не шаблона) вы можете указать желаемый ref
в createElement
параметры:
render: function (createElement) {
return createElement('div', { ref: 'root' })
}
// or, in short form:
render: h => h('div', { ref: 'root' })
первоначальный ответ:
Как указано в документации,
[...] концепции реактивных ссылок и шаблонных ссылок унифицированы в Vue 3.
И у вас также есть пример того, как ref
"корневой" элемент. Очевидно, вам не нужно называть его root. Назови это$el
, Если вы предпочитаете. Однако это не означает, что он будет доступен какthis.$el
, но this.$refs.$el
.
<template>
<div ref="root"></div>
</template>
<script>
import { ref, onMounted } from 'vue'
export default {
setup() {
const root = ref(null)
onMounted(() => {
// the DOM element will be assigned to the ref after initial render
console.log(root.value) // this is your $el
})
return {
root
}
}
}
</script>
В Vue 3 вы больше не ограничены только одним корневым элементом в <template>
, поэтому вам нужно специально ref
Отметьте любой элемент, с которым хотите взаимодействовать.
В Vue 3 + Composition API нет
$el
предусмотрена альтернатива.
Даже если вы используете Vue 3 с API параметров, из-за наличия фрагментов рекомендуется использовать шаблонные ссылки для прямого доступа к узлам DOM вместо того, чтобы полагаться на
this.$el
.
Как инициировать стороннюю библиотеку
Допустим, у нас есть элемент div для библиотеки третьей части:
<template>
Below we have a third-party-lib
<div class="third-party-lib"></div>
</template>
И затем мы хотим инициировать его из Javascript:
Решение 1 (рекомендуется): использование ссылок на шаблоны
<script setup>
import { ref, onMounted } from 'vue';
const $thirdPartyLib = ref(null); // template ref
onMounted(() => {
$thirdPartyLib.value.innerText = 'Dynamically loaded';
});
</script>
<template>
Below we have a third-party-lib
<div ref="$thirdPartyLib" class="third-party-lib"></div>
</template>
Решение 2 (не рекомендуется): использование недокументированного
@VnodeMounted
<script setup>
function initLib({ el }) {
el.innerText = 'Dynamic content';
}
</script>
<template>
Below we have a third-party-lib
<div class="third-party-lib" @VnodeMounted="initLib"></div>
</template>
Просто добавил сюда свои 2 цента и хотел исправить то, что говорят некоторые другие ответы, которых у Vue 3 больше нет.
Он все еще есть: https://vuejs.org/api/component-instance.html#el.
Его использование не рекомендуется в случае многокорневого, когда элемент не может быть определен как определенный корневой элемент, и для согласованности с однокорневыми компонентами (где $el работает так же, как Vue 2), документация предлагает вам вместо этого используйте $refs.
Для многокорневых компонентов ссылка находится на ближайшем текстовом узле перед элементами (или комментарием для гидратации SSR).
Это не означает, что это ненадежно, наоборот, поскольку этот механизм используется внутри и для гидратации SSR.
В большинстве случаев можно использовать
$refs
и вы должны.
Но если вы не можете, как в случае ниже, вы все равно можете положиться на:
<template>
# an empty text node exists here in the DOM.
<slot name="activator" :on="activatorEventHandlers">
<other-component />
</template>
В этом случае (случай всплывающих подсказок и контекстных меню, где прослушиватель событий прикреплен к пользовательскому слоту) первым элементом является слот, и вы не можете добавить ссылку на слот.
Итак, используя
$el
будет указывать на первый текстовый узел, поэтому
this.$el.nextElementSibling
будет элементом, переданным через пользовательский слот.
Вы действительно можете использовать
$el
на Vue 3. Однако это не рекомендуется.
import { getCurrentInstance } from 'vue';
const el = getCurrentInstance().ctx.$el;
Кажется, у этого есть полная функциональность $ el на Vue 2.