gpt4 book ai didi

细长包裹每个插槽

转载 作者:行者123 更新时间:2023-12-05 03:52:32 25 4
gpt4 key购买 nike

我希望在 svelte 中创建一个 Spacer 元素。我已经完成了我设定的目标,即允许用户将元素包装在 <Space></Space> 中。标记并传递 Prop 以垂直/水平均匀地间隔它们,甚至对齐内部元素中心/开始/结束/基线。我遇到的问题是我必须将每个子元素包装到 <Space></Space><SpaceItem></SpaceItem>以获得预期的效果。这是示例代码:

App.svelte

<script>
import {Space, SpaceItem} from './components/Space';
</script>

<Space>
<SpaceItem>
<Button primary>Primary</Button>
</SpaceItem>
<SpaceItem>
<Button primary icon="add">Primary</Button>
</SpaceItem>
<SpaceItem>
<Button danger>Danger</Button>
</SpaceItem>
</Space>

Space.svelte

<script>
import { SPACE } from './SpaceContext.svelte';
import { setContext } from 'svelte';
import { readable } from 'svelte/store';
export let vertical = false;
export let horizontal = true;
export let alignCenter = false;
export let alignStart = false;
export let alignEnd = false;
export let alignBaseline = false;
export let large = false;
export let middle = false;
export let size = null;

horizontal = vertical ? false : true;
size = size ? size : large ? 24 : middle ? 16 : 8;

const gap = readable(size);
const direction = readable(horizontal ? 'horizontal' : 'vertical');

setContext(SPACE, {
gap,
direction,
});
</script>

<style>
.space {
display: -webkit-inline-box;
display: -ms-inline-flexbox;
display: inline-flex;
}
.vertical {
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
}
.align-center {
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.align-start {
-webkit-box-align: start;
-ms-flex-align: start;
align-items: flex-start;
}
.align-end {
-webkit-box-align: end;
-ms-flex-align: end;
align-items: flex-end;
}
.align-baseline {
-webkit-box-align: baseline;
-ms-flex-align: baseline;
align-items: baseline;
}
</style>

<div
class="space"
class:horizontal
class:vertical
class:size
class:align-center={alignCenter}
class:align-start={alignStart}
class:align-end={alignEnd}
class:align-baseline={alignBaseline}>
<slot />
</div>

空间项目

<script>
import { SPACE } from './SpaceContext.svelte';
import { getContext } from 'svelte';
const { gap, direction } = getContext(SPACE);

let style;
if ($direction === 'horizontal') {
style = `margin-right: ${$gap}px;`;
} else {
style = `margin-bottom: ${$gap}px;`;
}
</script>

<style>

</style>

<div class="item" {style}>
<slot />
</div>

有没有办法消除 <SpaceItem></SpaceItem>元素和 <Space></Space>包装传递给其 <slot /> 的每个元素与 <SpaceItem></SpaceItem> ?我只想将所有元素包装在一个 Space 标签中,而不是将每个单独的元素包装在 SpaceItem 标签中。

期望的效果是让我能够写:

App.svelte

<script>
import {Space, SpaceItem} from './components/Space';
</script>

<Space>
<Button primary>Primary</Button>
<Button primary icon="add">Primary</Button>
<Button danger>Danger</Button>
</Space>

并且仍然用 <SpaceItem></SpaceItem> 包裹每个按钮在 Space.svelte 文件中。

最佳答案

这是我自己制定的解决方案,但我不确定这在实际应用程序中是否会出现任何性能问题,因此欢迎提出意见。

App.svelte

<script>
import Space from './Space.svelte';
import Button from './Button.svelte';
</script>

<Space>
<Button primary>Primary</Button>
<Button primary icon="add">Primary</Button>
<Button danger>Danger</Button>
</Space>

<Space vertical large alignCenter>
<Button primary icon="add">Primary</Button>
<Button danger>Danger</Button>
</Space>

Space.svelte

<script>
import { onMount } from 'svelte';
import addWrapper from './utils/addWrapper';
export let vertical = false;
export let horizontal = true;
export let alignCenter = false;
export let alignStart = false;
export let alignEnd = false;
export let alignBaseline = false;
export let large = false;
export let middle = false;
export let size = null;

horizontal = vertical ? false : true;
size = size ? size : large ? 24 : middle ? 16 : 8;

const gap = size;
const direction = horizontal ? 'horizontal' : 'vertical';
let style;

if (direction === 'horizontal') {
style = `margin-right: ${gap}px;`;
} else {
style = `margin-bottom: ${gap}px;`;
}
let currentEl;

onMount(async () => {
addWrapper({
node: currentEl,
tag: 'div',
style,
});
});
</script>

<style>
.space {
display: -webkit-inline-box;
display: -ms-inline-flexbox;
display: inline-flex;
}
.vertical {
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
}
.align-center {
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.align-start {
-webkit-box-align: start;
-ms-flex-align: start;
align-items: flex-start;
}
.align-end {
-webkit-box-align: end;
-ms-flex-align: end;
align-items: flex-end;
}
.align-baseline {
-webkit-box-align: baseline;
-ms-flex-align: baseline;
align-items: baseline;
}
</style>

<div
bind:this={currentEl}
class="space"
class:horizontal
class:vertical
class:align-center={alignCenter}
class:align-start={alignStart}
class:align-end={alignEnd}
class:align-baseline={alignBaseline}
>
<slot />
</div>

addWrapper.js

export default async function addWrapper({ node, tag, style }) {
const children = node.childNodes;
[].forEach.call(children, function (child) {
if (child.nodeName !== "#text" && child.nodeName !== "#comment") {
let wrapper = document.createElement(tag);
wrapper.setAttribute("style", style);
child.parentNode.insertBefore(wrapper, child);
wrapper.appendChild(child);
}
});
}

据说这可行,并且无需为简单情况创建单独的包装器,但更复杂的包装器将需要重新工作。如果有人有更简单、更高效的更好建议,我会洗耳恭听。

关于细长包裹每个插槽,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62157179/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com