如何访问另一个子组件中的插槽内容

How to access content of slot in another child component

以下问题:

我有一个 Vue.js 组件,它依赖于其父组件的 DOM。但是当 prop 通过时,它 (this.$el) 是未定义的,可能是因为它还没有安装。

我的组件的 vue 模板文件如下所示:

<template>
  <md-card>
    <md-card-content>
      <ol>
        <li v-for="item in headings(content)">
          <a :href="`#${item.id}`">{{ item.name }}</a>
        </li>
      </ol>
    </md-card-content>
  </md-card>
</template>
<script>
  export default {
    props: ['content'],
    methods: {
      headings(content) {
        // DOM element is used
        // At this moment, `content` is undefined
      },
    },
  };
</script>

使用上面那个的组件包含这段代码:

<article-index :content="this.$el"></article-index>

我想过等待父组件挂载,但那样我似乎无法像上面那样保留模板,因为它总是会立即尝试访问方法(或变量)。

我该如何解决这个问题?

编辑:

<template>
  <div class="content">
    <div class="left"><article-index :content="this.$el"></article-index></div>
    <div class="article"><slot></slot></div>
    <div class="right"><slot name="aside"></slot></div>
  </div>
</template>

这是父组件的模板。我真正需要的唯一东西是 .article div 或插槽的内容。

您可以使用 this.$slots 获取它,在父组件的挂载函数中您可以访问 this.$slots 并将其分配给一些可以传递给 article-index 组件的变量。

以下代码打印传递的插槽:

Vue.component('wrapper', {
    name: 'Wrapper',
  template: `<div><slot></slot></div>`,
  mounted () {
    this.$slots.default.forEach(vnode => { 
        console.log(vnode)
    })
  }
})

示例 fiddle here.

在@saurabh 的帮助下,我发现我可以直接访问我传递给 child 的插槽。

但核心问题依然存在:组件当时没有挂载。

所以我改变了我访问传递的插槽的方式。

我现在传递 parent 组件中的默认插槽,而不是 parent 元素。

由于 slots 道具是 VNode objects 的数组,我不能对它们使用任何 DOM 方法。但是由于 VNode 的榆树 属性 包含实际的 DOM 元素,我正在使用它。

同样,问题:尚未安装。

这就是为什么 v-for 现在指向 headings 数据,而不是已删除的方法。 相反,我添加了一个 mounted() 方法,当组件安装时 Vue 会自动调用该方法。

调用该方法时,插槽已安装,因此我可以访问它们的 elm 属性。在我的例子中,有多个默认槽,所以 slots 数组有多个项目。为了能够调用特定的 querySelectorAll,我添加了一些功能性的 Array 魔法。

编辑:由于直接访问渲染内容上的 querySelector 更有意义,我现在传递 $refs 属性而不是 $slots。 即使我只需要 $refs.article,如果我直接传递它,我也会得到 undefined。通过将 this.$refs 作为一个整体传递,child 组件可以访问文章引用,即使它在安装之前不存在。

所以这是我的新 parent 组件:

<template>
  <div class="content">
    <div class="left">
      <article-index :refs="this.$refs"></article-index>
    </div>
    <div class="article" ref="article"><slot></slot></div>
    <div class="right"><slot name="aside"></slot></div>
  </div>
</template>

和 child:

<template>
  <md-card>
    <md-card-content>
      <ol>
        <li v-for="item in headings">
          <a @click="scroll(item.id)" :href="hash">
            {{ item.name }}
          </a>
        </li>
      </ol>
    </md-card-content>
  </md-card>
</template>
<script>
  import dashify from 'dashify';

  export default {
    props: ['refs'],
    data: () => ({
      headings: {},
      hash: location.hash,
    }),
    methods: {
      scroll(to) {
        this.refs.article.querySelector(`#${to}`).scrollIntoView();
      },
    },
    mounted() {
      const elements = Array.from(this.refs.article.querySelectorAll('h2'));
      elements.forEach(node => node.id = dashify(node.innerText));

      this.headings = elements.map(node => ({
        name: node.innerText,
        id: node.id,
      }));
    },
  };
</script>