【问题标题】:How to access content of slot in another child component如何访问另一个子组件中的插槽内容
【发布时间】:2017-05-22 05:08:08
【问题描述】:

以下问题:

我有一个依赖于其父 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>

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

【问题讨论】:

  • 你为什么要在 prop 中传递this.$el?
  • @saurabh 因为我需要访问 DOM 元素才能执行 querySelector。你会怎么做?
  • 我会尝试在那里传递一个 vue 变量,您能否也添加您的父 DOM 的 HTML,并指出您想要访问的确切内容。
  • @saurabh 这样做了
  • @saurabh 我看到你编辑了标题...好吧,我不知道我是如何访问插槽 DOM 的????

标签: javascript vue.js vue-loader


【解决方案1】:

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

小提琴样本here.

【讨论】:

  • 所以我不能像这样使用 querySelector 这样的方法,对吧?
  • 您可以使用vnode.elm访问vnode的HTML。 jsfiddle.net/mimani/hd1n41he/1
  • * 因为该元素尚未安装。
  • 但是,如果我 v-for 在标题上,“它总是会尝试立即访问方法(或变量)”(请参阅​​问题)。
  • @22samuelk 查看更新的fiddle,它将插槽的内容放在变量中并单独打印在视图中。
【解决方案2】:

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

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

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

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

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

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

这就是为什么 v-for 现在指向 headings 数据,而不是删除的方法。 相反,我添加了一个 mounted() 方法,当组件被挂载时,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>

【讨论】:

    猜你喜欢
    • 2021-07-08
    • 1970-01-01
    • 1970-01-01
    • 2021-02-01
    • 2020-03-23
    • 2019-09-29
    • 2018-06-01
    • 1970-01-01
    • 2019-11-11
    相关资源
    最近更新 更多