Vue 3 Composition API - 如何获取组件所在的组件元素($el)?

问题描述 投票:0回答:4

我想用

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

setup(props, context) {
    onMounted(() => {
        interact($el)
            .resizable();
    })
}
vue.js vue-composition-api vuejs3
4个回答
87
投票

tl;博士:

在 Vue 3 中,组件不再仅限于 1 个根元素。隐含地,这意味着您不再拥有

$el

您必须使用

ref
与模板中的任何元素进行交互:

<div ref="root" />

setup
函数中,您应该将
root
实例化为
const root = ref(null)

在选项 API 中,您可以在任何方法或挂钩中使用

this.$refs.root
,只要它位于
mounted()
之后即可。

正如@AndrewSee在评论中指出的,当使用渲染函数(而不是模板)时,您可以在

ref
选项中指定所需的
createElement

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

初步回答:

文档中所述,

[...] reactive refstemplate refs 的概念在 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
erence 想要与之交互的任何元素。


更新,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>

7
投票

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

$el
的内容。

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

在多根情况下不鼓励使用它,其中

$el
元素无法确定为特定的根元素,并且为了保持一致性与单根组件(其中$el的工作方式与Vue相同) 2),文档建议您使用 $refs 代替。

对于多根组件,

$el
ref 位于元素之前最近的文本节点(或 SSR 水合的注释)。

这并不意味着

$el
不可靠,相反,因为该机制是内部使用的并且用于SSR水合作用。

在大多数情况下,您可以使用

$refs
并且您应该使用。

但如果你不能,就像下面的例子,你仍然可以信赖

$el
:

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

在这种情况下(工具提示和上下文菜单的情况,其中事件侦听器附加到用户槽),第一个元素是槽,并且您无法在槽上添加引用。

因此使用

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


6
投票

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

即使您使用带有Options API的Vue 3,由于Fragments的可用性,建议使用模板引用来直接访问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>

实时查看两种解决方案


0
投票

有些答案给出了很好的方法,我会添加两个方法。

一个:

instance.proxy.$el
拖曳:
onVnodeMounted
挂钩

<script setup>
const instance = getCurrentInstance()
onMounted(() => {
  console.log(instance.proxy.$el)
})
function onVNodeMounted(VNode) {
  console.log('onVNodeMounted', VNode.el)
}
</script>

<template>
  <div :onVnodeMounted="onVNodeMounted">
  </div>
</template>

注意 @VnodeMounted="onVNodeMounted" 当我回答时不起作用。 Vue的版本是3.3.4.

Plus

onVnodeMounted
onVnodeUpdated
没有放在vue的文档中,将来可能会更改。您可以在模板和 jsx 中使用它们。
getCurrentInstance
更好。

使用getCurrentInstance时,注意模板构建。

<script setup>
const instance = getCurrentInstance()
onMounted(() => {
  console.log(instance.proxy.$el)
  console.log(instance.proxy.$el.nextElementSibling)
})
</script>

<template>
  <!-- comment -->
  <div>
    get #text node by proxy.$el . nextElementSibling is root node
  </div>
</template>

proxy.$el
也是文本节点。

<script setup>
const instance = getCurrentInstance()
onMounted(() => {
  console.log(instance.proxy.$el)
  console.log(instance.proxy.$el.nextElementSibling)
})
</script>

<template>
  <div>tow root</div>
  <div>
    get #text node by proxy.$el . nextElementSibling is first div
  </div>
</template>
© www.soinside.com 2019 - 2024. All rights reserved.