Передача слота в слот
Я создаю небольшую библиотеку, которая позволит изменять части макета приложения из других компонентов.
Основная идея состоит в том, что наличие основного компонента навигации:
<template>
<div class='main-navigation>
<div class='logo'><img...>
<div class='actions'>
<Container name='extra-actions' />
<a href="some-action">Action</a>
</div>
</template>
Затем компонент может зарегистрировать дополнительный контент с помощью:
<template>
<div class='home-page'>
<ContentFor container="extra-actions">
<a href='some-home-specific-action'>Do sth extra</a>
</ContentFor>
...rest of the page
</div>
</template>
Мне удалось заставить вышеуказанное работать, используя настраиваемые подключаемые модули и служебные объекты, регистрирующие (и обновляющие) слоты как VNode, как определено в ContentFor, и отображая их в контейнере. Теперь я хотел бы улучшить его, позволив пользователю добавлять настраиваемый макет для каждого содержимого, например:
<ul class='actions'>
<Container name='extra-actions'>
<li><slot></slot></li>
</Container>
</ul>
Это красиво отделит компонент представления от структуры навигации. Я пробовал следующее:
render (h) {
return h(Fragment, Object.values(this.contents).map((content) => {
if (this.$scopedSlots.default) {
return this.$scopedSlots.default({
slots: { default: content.slot } # this does nothing!
})
} else {
# This works as expected
return content.slot
}
}))
},
Вышеуказанное отлично работает, когда нет настраиваемого шаблона. Когда пользовательский шаблон присутствует, он отображает этот шаблон, но не передает содержимое в слот шаблона, в результате чего:
<ul class='actions'>
<li></li> # instead of <li><a href='some-home-specific-action'>Do sth extra</a></li>
</ul>
Есть ли какой-то конкретный способ передачи областей видимости другим областям действия?
1 ответ
Так что, пройдя вперед и назад с этим, я узнал, что невозможно решить мой шаблон со слотом. Когда я делаю
# layout/Navigation.vue
<ul>
<Container name='main-nav-actions>
<li><slot/></li>
</Container>
</ul>
</slot>
разрешается в контексте компонента навигации - то есть на данный момент это статический массив VNodes. По этой причине слоты не могут иметь свои собственные динамические вложенные слоты.
Вместо этого мне пришлось написать функциональный компонент, отвечающий за рендеринг VNodes:
export {
name: 'RenderContent',
functional: true,
render (h, { props }) { return props.content }
}
После этого я могу создать свой шаблон с помощью scopedSlot:
<Container name='main-nav-actions vue-slot="{ content }">
<li><RenderContent :content="content"></li>
</Container>
Это не самое красивое решение, но, похоже, оно работает, позволяет передавать необязательные параметры через ContentFor, что довольно здорово.