如何使用vue3获取插槽中的HTMLElements?
<p>当我尝试开发 Layer 组件时发生了一些事情。代码如下:</p>
<p><em>// Wrapper.vue</em></p>
<pre class="brush:php;toolbar:false;"><template>
<slot v-bind="attrs"></slot>
</template>
<script lang="ts" setup>
import {
defineProps,
ref,
watch,
useAttrs,
onMounted,
onUnmounted,
getCurrentInstance,
} from "vue";
const props = defineProps({
name: { type: String, default: "" },
zIndex: { type: Number, default: 0 },
});
const attrs = useAttrs();
const inst = getCurrentInstance();
const observer = ref<MutationObserver | null>(null);
watch(
() => [props.zIndex, props.name],
() => {
setBrothersAttrs();
}
);
onMounted(() => {
let el = inst?.vnode.el;
if (el) {
if (!observer.value)
observer.value = new MutationObserver(setBrothersAttrs);
observer.value.observe(el.parentElement, { childList: true });
}
setBrothersAttrs();
});
onUnmounted(() => {
if (observer.value) observer.value.disconnect();
});
const setBrothersAttrs = () => {
let el = inst?.vnode.el;
let children = el?.parentElement?.children;
if (el && children) {
for (let i = 0; i < children.length; i++) {
let bro = children[i];
if (bro === el) continue;
bro.style.zIndex = props.zIndex;
}
}
};
</script></pre>
<p><em>// Test.vue</em></p>
<pre class="brush:php;toolbar:false;"><template>
<div class="test">
<Wrapper name="wrapper1" :z-index="1">
<img class="picture1" />
<div class="inner">
<Wrapper name="wrapper2" :z-index="2">
<img class="picture2" />
</Wrapper>
</div>
<Wrapper name="wrapper3" :z-index="3">
<img class="picture3" />
</Wrapper>
</Wrapper>
</div>
</template>
<script lang="ts" setup>
import Wrapper from "./Wrapper.vue";
</script></pre>
<p><em>// HTML 格式的结果:</em></p>
<pre class="brush:php;toolbar:false;"><div class="test">
<img class="picture1" style="z-index: 1" /><!-- if no wrapper3, "z-index: 3" -->
<div class="inner" style="z-index: 1">
<img class="picture2" style="z-index: 2" />
</div>
<img class="picture3" style="z-index: 1" /><!-- if no wrapper3, "z-index: 3" -->
</div></pre>
<blockquote>
<p>如上面的代码,组件Wrapper是一个空组件。其目的是在 slot["default"] 中设置 HTMLElements 的 z-index。</p>
</blockquote>
<p>不幸的是,我在 useSlots()["default"] 中找不到子元素。 <strong>所以我尝试让一个突变观察者来观察父级的childList。</strong></p>
<p>它单独工作得很好(<em>就像示例中的图片1和图片2</em>)。 <strong>但是当多个 Wrapper 包裹在一起时,它会相互覆盖(<em>就像示例中的图片3,由wrapper3设置的picture3的z索引被wrapper1覆盖)。</strong>这意味着它们共享相同的父级,以便父级的子级始终相同。</p>
<p>所以现在问题又变成了“<strong>如何在槽中获取HTMLElements</strong>”......任何vuejs大师都可以帮我吗?</p>
使用 Vue 渲染函数可以更简单地完成:渲染槽
const { createApp, h } = Vue; const Wrapper = { props: { name: { type: String, default: "" }, zIndex: { type: Number, default: 0 }, }, setup(props, { slots }) { let children = slots.default(); if (children) { for (let i = 0; i < children.length; i++) { children[i].props.style = `z-index: ${props.zIndex}`; } } return () => slots.default() } } const App = { components: { Wrapper } } const app = createApp(App) const vm = app.mount('#app')#app { line-height: 2; } [v-cloak] { display: none; }<div id="app" v-cloak> <div class="test"> Test <Wrapper name="wrapper1" :z-index="1"> <img class="picture1" /> <div class="inner"> <Wrapper name="wrapper2" :z-index="2"> <img class="picture2" /> </Wrapper> </div> <Wrapper name="wrapper3" :z-index="3"> <img class="picture3" /> </Wrapper> </Wrapper> </div> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>