如何使用vue3获取插槽中的HTMLElements?
P粉794177659
P粉794177659 2023-09-01 17:57:52
[Vue.js讨论组]

当我尝试开发 Layer 组件时发生了一些事情。代码如下:

// Wrapper.vue

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

// Test.vue

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

// HTML 格式的结果:

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

如上面的代码,组件Wrapper是一个空组件。其目的是在 slot["default"] 中设置 HTMLElements 的 z-index。

不幸的是,我在 useSlots()["default"] 中找不到子元素。 所以我尝试让一个突变观察者来观察父级的childList。

它单独工作得很好(就像示例中的图片1和图片2)。 但是当多个 Wrapper 包裹在一起时,它会相互覆盖(就像示例中的图片3,由wrapper3设置的picture3的z索引被wrapper1覆盖)。这意味着它们共享相同的父级,以便父级的子级始终相同。

所以现在问题又变成了“如何在槽中获取HTMLElements”......任何vuejs大师都可以帮我吗?

P粉794177659
P粉794177659

全部回复(1)
P粉714890053

使用 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>
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号