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

时间:2017-01-07 14:41:36

标签: javascript vue.js vue-loader

以下问题:

我有一个依赖于其父DOM的Vue.js组件。但是当道具通过的那一刻,它(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或插槽的内容。

2 个答案:

答案 0 :(得分:4)

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

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

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

示例小提琴here

答案 1 :(得分:0)

在@saurabh的帮助下,我能够发现我可以直接访问我传给孩子的插槽。

但核心问题仍然存在:当时没有安装组件。

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

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

由于slots prop是VNode个对象的数组,我不能在它们上使用任何DOM方法。但由于VNode的elm属性包含实际的DOM元素,我正在使用它。

同样,问题是:它还没有安装。

这就是v-for现在指向headings数据的原因,而不是删除的方法。 相反,我添加了一个mounted()方法,当组件挂载时,Vue会自动调用它。

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

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

所以这是我新的父组件:

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

和孩子:

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