如何使用 createElement 创建槽的副本?
How to create a copy of the slot with createElement?
如何获取插槽组件的名称?
我想创建插槽中提供的组件的副本:
const child1 = slot
const child2 = h(???, slot.props)
以便 child1
完全呈现 child2
。
我需要这个,以便我可以更改该 VNode 的属性,例如 类。
上下文
import { h } from 'vue';
export default {
setup(props, { slots }) {
const children = [];
for (const slot of slots.default()) {
const child = h(???, slot.props)
children.push(h('div', [child]));
}
return () =>
h('div', children);
},
};
背景
我想做一个类似于q-button-group的组件:
我需要 2 个组件 TButton
和 TButtonGroup
以便我可以独立地设置 TButton
样式并通过将这些按钮放在 TButtonGroup
.[=25 中来创建组=]
例子
<TButtonGroup>
<TButton label="Two" />
<TButton label="Three" />
</TButtonGroup>
TButton
应该有一个不同的列表 类:
- 当它在 TButtonGroup 内时:
px-4 py-2
- 如果不是:
border rounded-lg px-4 py-2
游乐场
https://stackblitz.com/edit/vue3-button-group-razbakov?file=src%2Fcomponents%2FGroupRender.js
vnode的组件名就不多说了,此时组件已经解析了。 VNode的元素或组件存储在type
属性.
您的方法的问题在于渲染函数是组件模板的替代方法,而不是访问整个 DOM 元素层次结构的方法。渲染函数中不会有 TButton
子元素,如 div
,只有 TButton
vnode 本身。需要渲染它才能访问其子项。
如果 TButton
是需要修改初始行为的其他组件,这可以通过向其添加一些指令并访问组件的子元素来完成。
但是由于 TButton
是您自己的组件,可以根据您的需要进行修改,所以最直接的方法是根据道具更改 类 并在其内部提供此道具 TGroup
,即:
const child = h(slot.type, {...slot.props, group: true}, slot.children);
children.push(child);
使用您创建的组件类型:
const { h } = Vue
const TBtn = {
props: {
staticClass: {
type: Array,
default: () => [],
},
},
template: `
<div
class="t-btn px-4 py-2"
>
<slot></slot>
</div>
`
}
const TBtnGroup = {
setup(props, {
slots
}) {
const children = [...slots.default()]
.map(slot => h(slot.type, {
class: ['border', 'rounded-lg']
}, slot))
return () => h('div', {
class: ['d-flex']
}, children)
},
}
const App = {
template: `
<t-btn>OUTSIDE 1</t-btn>
<t-btn>OUTSIDE 2</t-btn>
<br />
<t-btn-group>
<t-btn>INSIDE 1</t-btn>
<t-btn>INSIDE 2</t-btn>
<t-btn>INSIDE 3</t-btn>
</t-btn-group>
`
}
const app = Vue.createApp(App)
app.component('TBtn', TBtn)
app.component('TBtnGroup', TBtnGroup)
app.mount('#app')
.px-4 {
padding-left: 16px;
padding-right: 16px;
}
.py-2 {
padding-top: 8px;
padding-bottom: 8px;
}
.border {
border: 1px solid black;
}
.rounded-lg {
border-radius: 8px;
}
.d-flex {
display: flex;
gap: 8px;
}
.t-btn:hover {
cursor: pointer;
background-color: black;
color: white;
}
<script src="https://unpkg.com/vue@next"></script>
<div id="app"></div>
如何获取插槽组件的名称?
我想创建插槽中提供的组件的副本:
const child1 = slot
const child2 = h(???, slot.props)
以便 child1
完全呈现 child2
。
我需要这个,以便我可以更改该 VNode 的属性,例如 类。
上下文
import { h } from 'vue';
export default {
setup(props, { slots }) {
const children = [];
for (const slot of slots.default()) {
const child = h(???, slot.props)
children.push(h('div', [child]));
}
return () =>
h('div', children);
},
};
背景
我想做一个类似于q-button-group的组件:
我需要 2 个组件 TButton
和 TButtonGroup
以便我可以独立地设置 TButton
样式并通过将这些按钮放在 TButtonGroup
.[=25 中来创建组=]
例子
<TButtonGroup>
<TButton label="Two" />
<TButton label="Three" />
</TButtonGroup>
TButton
应该有一个不同的列表 类:
- 当它在 TButtonGroup 内时:
px-4 py-2
- 如果不是:
border rounded-lg px-4 py-2
游乐场
https://stackblitz.com/edit/vue3-button-group-razbakov?file=src%2Fcomponents%2FGroupRender.js
vnode的组件名就不多说了,此时组件已经解析了。 VNode的元素或组件存储在type
属性.
您的方法的问题在于渲染函数是组件模板的替代方法,而不是访问整个 DOM 元素层次结构的方法。渲染函数中不会有 TButton
子元素,如 div
,只有 TButton
vnode 本身。需要渲染它才能访问其子项。
如果 TButton
是需要修改初始行为的其他组件,这可以通过向其添加一些指令并访问组件的子元素来完成。
但是由于 TButton
是您自己的组件,可以根据您的需要进行修改,所以最直接的方法是根据道具更改 类 并在其内部提供此道具 TGroup
,即:
const child = h(slot.type, {...slot.props, group: true}, slot.children);
children.push(child);
使用您创建的组件类型:
const { h } = Vue
const TBtn = {
props: {
staticClass: {
type: Array,
default: () => [],
},
},
template: `
<div
class="t-btn px-4 py-2"
>
<slot></slot>
</div>
`
}
const TBtnGroup = {
setup(props, {
slots
}) {
const children = [...slots.default()]
.map(slot => h(slot.type, {
class: ['border', 'rounded-lg']
}, slot))
return () => h('div', {
class: ['d-flex']
}, children)
},
}
const App = {
template: `
<t-btn>OUTSIDE 1</t-btn>
<t-btn>OUTSIDE 2</t-btn>
<br />
<t-btn-group>
<t-btn>INSIDE 1</t-btn>
<t-btn>INSIDE 2</t-btn>
<t-btn>INSIDE 3</t-btn>
</t-btn-group>
`
}
const app = Vue.createApp(App)
app.component('TBtn', TBtn)
app.component('TBtnGroup', TBtnGroup)
app.mount('#app')
.px-4 {
padding-left: 16px;
padding-right: 16px;
}
.py-2 {
padding-top: 8px;
padding-bottom: 8px;
}
.border {
border: 1px solid black;
}
.rounded-lg {
border-radius: 8px;
}
.d-flex {
display: flex;
gap: 8px;
}
.t-btn:hover {
cursor: pointer;
background-color: black;
color: white;
}
<script src="https://unpkg.com/vue@next"></script>
<div id="app"></div>