Vue 3 Composition API - 如何获取挂载组件的组件元素($el)

Vue 3 Composition API - How to get the component element ($el) on which component is mounted

我想用onMounted启动第三方库。为此,我需要组件元素作为其上下文。在 Vue 2 中,我会使用 this.$el 来获取它,但不确定如何使用组合函数来获取它。 setup 有两个参数,其中 none 包含元素。

setup(props, context) {
    onMounted(() => {
        interact($el)
            .resizable();
    })
}

tl;博士:

在 Vue 3 中,组件不再仅限于 1 个根元素。隐含地,这意味着您不再有 $el.
您必须使用 ref 与模板中的任何元素进行交互:

<div ref="root" />

setup函数中,您应该将root实例化为const root = ref(null)
在 Options API 中,你可以在任何方法或钩子中使用 this.$refs.root,只要它在 mounted().
之后 正如@AndrewSee 在评论中指出的那样,当使用渲染函数(不是模板)时,您可以在 createElement 选项中指定所需的 ref

render: function (createElement) {
  return createElement('div', { ref: 'root' })
}
// or, in short form:
render: h => h('div', { ref: 'root' })

初始答案:

docs

中所述

[...] the concepts of reactive refs and template refs are unified in 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> 中的一个根元素,因此您必须明确地 reference 任何您想与之交互的元素。


更新,2 年后。
各种组件样式的具体语法(它们不是不同的解决方案,它们是同一事物的不同写法):

<script setup>:

<script setup>
import { ref, onMounted } from 'vue';
const root = ref(null);
onMounted(() => console.log(root.value.outerHTML));
</script>
<template>
  <div ref="root" />
</template>

<script setup lang="ts">:

<script setup lang="ts">
import { ref, onMounted } from 'vue';
const root = ref<HTMLElement | null>(null);
onMounted(() => { console.log(root.value?.outerHTML) );
</script>
<template>
  <div ref="root" />
</template>

选项API:

<script>
  export default {
    mounted() {
      console.log(this.$refs.root.outerHTML);
    }
  }
</script>
<template>
  <div ref="root" />
</template>

在 Vue 3 + Composition API 中没有提供 $el 替代方案。

即使您使用带选项 API 的 Vue 3,由于片段的可用性,建议使用模板引用直接访问 DOM 节点,而不是依赖 this.$el.


如何发起third-part-library

假设我们有一个 div 元素用于 third-part-library:

<template>
  Below we have a third-party-lib
  <div class="third-party-lib"></div>
</template>

然后我们想从 Javascript:

启动它

Solution 1 (recommended): Using template refs

<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>

Solution 2 (not recommended): Using non-documented @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>

See both solutions live

只是在这里添加我的 2 美分,并想更正一些其他答案所说的 Vue 3 不再有 $el

它还有它: https://vuejs.org/api/component-instance.html#el.

不鼓励使用它 在 multi-root 的情况下 $el 元素无法确定为特定的根元素,并且 为了与 single-root 组件保持一致(其中 $el 的工作方式与 Vue 2 相同),文档建议您改用 $refs。

对于 multi-root 组件,$el ref 位于元素之前最近的文本节点(或 SSR hydration 的注释)。

这并不意味着$el不可靠,相反,因为这种机制是内部使用的,用于SSR水合作用。

在大多数情况下,您可以使用 $refs,您应该这样做。

但如果你不能,就像下面的情况,你仍然可以依靠 $el:

<template>
  # an empty text node exists here in the DOM.
  <slot name="activator" :on="activatorEventHandlers">
  <other-component />
</template>

在这种情况下(事件侦听器附加到用户槽的工具提示和上下文菜单的情况),第一个元素是槽,您不能在槽上添加 ref。

因此使用 $el 将指向第一个文本节点,因此 this.$el.nextElementSibling 将是通过用户槽指定的元素。