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.

Другие вопросы по тегам