3

以下问题:

我有一个依赖于其父 DOM 的 Vue.js 组件。但是当 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>

这是父组件的模板。我真正需要的只是.articlediv 或插槽的内容。

4

2 回答 2

5

您可以使用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)
    })
  }
})

样品小提琴在这里

于 2017-01-07T15:18:30.050 回答
0

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

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

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

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

由于slot道具是一个VNode对象数组,因此我不能对它们使用任何 DOM 方法。但是由于 aVNode的 elm 属性包含实际的 DOM 元素,所以我使用它来代替。

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

这就是为什么v-fornow 指向headings数据,而不是删除的方法。相反,我添加了一个mount()方法,当组件被挂载时,Vue 会自动调用该方法。

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

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

所以这是我的新父组件:

<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>
于 2017-01-07T16:13:54.573 回答