如何从插槽中的子组件获取 HTMLElement?

wow*_*w64 6 vue.js vuejs3

如何获取槽中子元素的 Dom 元素。尝试在生命钩子 onMounted() 中获取一个对象的 el vnode 属性为 null

我的组件:

<template>
   <div>{{text}}</div>
   <slot></slot>
</template>

<script lang="ts">
import { defineComponent, onMounted } from "vue";

export default defineComponent({
    name: "my-component",
    props: {
        text: {
            type: String,
            default: '',
            required: true,
        },
    },
    setup( _, ctx) {
        
        onMounted( () => {
            if (ctx.slots.default) {
                console.log( (ctx.slots.default()[0]) ); // <- property "el" - is null
            }
        })

    },
});
</script>
Run Code Online (Sandbox Code Playgroud)

Dan*_*iel 3

需要记住的几件事(对于其他想要做同样事情的人)

\n
    \n
  • \xe2\x9c\x85 slot对象是通过上下文传入的,这是第二个参数
  • \n
  • \xe2\x9c\x85 默认情况下访问未命名的插槽内容
  • \n
  • \xe2\x9c\x85slots.default是需要执行的函数
  • \n
  • \xe2\x9c\x85slots.default()返回一个数组,因为一个槽可以有多个元素,大多数情况下你可以只选择[0]
  • \n
  • \xe2\x9d\x8c 内容仅在组件渲染后才可用。在我使用的示例中onMounted,这可能是最简单的。
  • \n
  • 但是,如果传递的元素是 Vue 组件,则该元素根本不可用
  • \n
\n

该槽可通过一个函数来访问slots.default(),该函数采用用于渲染该槽的数据参数。如果您想使用渲染函数,这对于生成节点非常有用,并且在很大程度上似乎只是一些暴露的内部结构。

\n

我发现了一些技巧来使用节点遍历来绕过它。

\n

一种(可能是更好的选择)使用子对象 ( slots.default()[0].children.default()[0].el.parentElement)

\n

另一个使用 aref和 a nextElementSibling

\n

这个想法是你放置一个跨度(或其他一些“不可见”元素),你可以使用它来引用ref。然后在onMounted处理程序中,您可以使用该元素来获取将成为下一个同级元素的槽元素。

\n

\r\n
\r\n
var app = Vue.createApp({\n  setup() {return {}}\n});\n\napp.component("parent-component", {\n  template: `<div><span ref="slotRef"></span><slot></slot></div>`,\n  setup(props, ctx) {\n    const slotRef = Vue.ref(null); // create a ref\n    Vue.onMounted(()=>{\n      const defaultSlot = ctx.slots.default();\n      console.log(defaultSlot[0].children.default()[0].el.parentElement) // or get the parent of the first child\n      defaultSlot[0].children.default()[0].el.parentElement.innerText += ""\n      console.log(slotRef.value.nextElementSibling); // get the Sibling of ref\n      slotRef.value.nextElementSibling.innerText += ""\n    })\n    return {slotRef};\n  }\n});\napp.component("child-component", {\n  template: `<div><slot></slot></div>`,\n});\n\napp.mount("#app");
Run Code Online (Sandbox Code Playgroud)\r\n
div{border:1px solid; padding:2px;}
Run Code Online (Sandbox Code Playgroud)\r\n
<script src="https://unpkg.com/vue@3.0.11/dist/vue.global.prod.js"></script>\n<div id="app">\n  <parent-component>\n    <child-component>\n      \n    </child-component>\n  </parent-component>\n</div>
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

  • 另外,请查看这个使用渲染函数和“withDirectives”的示例 https://jsfiddle.net/skirtle/rsnLda05/ 作为另一个选项 (2认同)