如何访问另一个子组件中的插槽内容
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>
以下问题:
我有一个 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>