✨(component): [space]新增 space 组件
This commit is contained in:
26
package/component/src/component/space/Renderer.ts
Normal file
26
package/component/src/component/space/Renderer.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
import type { PropType } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "Renderer",
|
||||
props: {
|
||||
renderFn: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
data: {
|
||||
type: Object as PropType<Record<string, any>>,
|
||||
default: undefined,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
return () => {
|
||||
if (typeof props.renderFn !== "function") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return props.renderFn(props.data);
|
||||
};
|
||||
},
|
||||
});
|
||||
42
package/component/src/component/space/index.less
Normal file
42
package/component/src/component/space/index.less
Normal file
@@ -0,0 +1,42 @@
|
||||
.layui-space {
|
||||
display: inline-flex;
|
||||
|
||||
&-horizontal {
|
||||
.layui-space-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
&-vertical {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&-wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
&-fill {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
&-align-start {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
&-align-center {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&-align-end {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
&-align-baseline {
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
&-item {
|
||||
width: inherit;
|
||||
}
|
||||
}
|
||||
5
package/component/src/component/space/index.ts
Normal file
5
package/component/src/component/space/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { withInstall, WithInstallType } from "../../utils";
|
||||
import Component from "./index.vue";
|
||||
|
||||
const component: WithInstallType<typeof Component> = withInstall(Component);
|
||||
export default component;
|
||||
132
package/component/src/component/space/index.vue
Normal file
132
package/component/src/component/space/index.vue
Normal file
@@ -0,0 +1,132 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "LaySpace",
|
||||
};
|
||||
</script>
|
||||
<script lang="ts" setup>
|
||||
import "./index.less";
|
||||
import {
|
||||
computed,
|
||||
h,
|
||||
useSlots,
|
||||
Comment,
|
||||
VNode,
|
||||
Fragment,
|
||||
isVNode,
|
||||
createTextVNode,
|
||||
VNodeArrayChildren,
|
||||
StyleValue,
|
||||
} from "vue";
|
||||
import Renderer from "./Renderer";
|
||||
|
||||
export type SpaceSize = "lg" | "md" | "sm" | "xs" | number | string;
|
||||
|
||||
export interface LaySpaceProps {
|
||||
/* 对齐方式 */
|
||||
align?: "start" | "end" | "center" | "baseline";
|
||||
/* 间距方向 */
|
||||
direction?: "horizontal" | "vertical";
|
||||
/* 子元素是否填充父容器 */
|
||||
fill?: boolean;
|
||||
/* 间距大小 */
|
||||
size?: SpaceSize | [SpaceSize, SpaceSize];
|
||||
/* 是否自动折行 */
|
||||
wrap?: boolean;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<LaySpaceProps>(), {
|
||||
align: "center",
|
||||
direction: "horizontal",
|
||||
size: "sm",
|
||||
});
|
||||
|
||||
const slots = useSlots();
|
||||
|
||||
const extractChildren = () => {
|
||||
const result: VNode[] = [];
|
||||
const children = slots.default && (slots?.default() as VNodeArrayChildren);
|
||||
const elementData = Array.isArray(children) ? [...children] : [];
|
||||
|
||||
while (elementData.length) {
|
||||
const vnode = elementData.shift();
|
||||
|
||||
if (vnode === null) continue;
|
||||
|
||||
if (Array.isArray(vnode)) {
|
||||
elementData.unshift(...vnode);
|
||||
}
|
||||
|
||||
if (!isVNode(vnode) || vnode.type === Comment) continue;
|
||||
|
||||
if (vnode.type === Fragment && Array.isArray(vnode.children)) {
|
||||
elementData.unshift(vnode.children);
|
||||
} else if (typeof vnode === "string" || typeof vnode === "number") {
|
||||
result.push(createTextVNode(vnode));
|
||||
} else {
|
||||
result.push(vnode);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const spaceClass = computed(() => [
|
||||
"layui-space",
|
||||
{
|
||||
[`layui-space-align-${props.align}`]: props.align,
|
||||
[`layui-space-${props.direction}`]: props.direction,
|
||||
[`layui-space-wrap`]: props.wrap,
|
||||
[`layui-space-fill`]: props.fill,
|
||||
},
|
||||
]);
|
||||
|
||||
const spaceStyle = computed(() => {
|
||||
const sizeMap = { xs: "4px", sm: "8px", md: "16px", lg: "24px" };
|
||||
let gap = "";
|
||||
|
||||
if (Array.isArray(props.size)) {
|
||||
gap = props.size
|
||||
.map((size) => {
|
||||
if (typeof size === "number") {
|
||||
return `${size}px`;
|
||||
}
|
||||
if (typeof size === "string") {
|
||||
return sizeMap[props.size as keyof Omit<SpaceSize, number>] || size;
|
||||
}
|
||||
return size;
|
||||
})
|
||||
.join(" ");
|
||||
} else if (typeof props.size === "string") {
|
||||
gap = sizeMap[props.size as keyof Omit<SpaceSize, string>] || props.size;
|
||||
} else if (typeof props.size === "number") {
|
||||
gap = `${props.size}px`;
|
||||
}
|
||||
|
||||
return {
|
||||
gap,
|
||||
};
|
||||
});
|
||||
|
||||
const itemStyle = computed<StyleValue>(() => [
|
||||
props.fill ? { flexGrow: 1, minWidth: "100%" } : {},
|
||||
]);
|
||||
|
||||
const children = extractChildren();
|
||||
|
||||
const renderSpaceItems = () =>
|
||||
children.map((child, index) => {
|
||||
return h(
|
||||
"div",
|
||||
{
|
||||
class: "layui-space-item",
|
||||
style: itemStyle.value,
|
||||
},
|
||||
h(child)
|
||||
);
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div :class="spaceClass" :style="spaceStyle">
|
||||
<Renderer :renderFn="renderSpaceItems"></Renderer>
|
||||
</div>
|
||||
</template>
|
||||
@@ -88,6 +88,7 @@ import LayNoticeBar from "./component/noticeBar/index";
|
||||
import LayPageHeader from "./component/pageHeader/index";
|
||||
import LayCascader from "./component/cascader/index";
|
||||
import LayAffix from "./component/affix/index";
|
||||
import LaySpace from "./component/space/index";
|
||||
import LayConfigProvider from "./provider";
|
||||
import { InstallOptions } from "./types";
|
||||
|
||||
@@ -174,6 +175,7 @@ const components: Record<string, Plugin> = {
|
||||
LayPageHeader,
|
||||
LayCascader,
|
||||
LayAffix,
|
||||
LaySpace,
|
||||
};
|
||||
|
||||
const install = (app: App, options?: InstallOptions): void => {
|
||||
@@ -267,6 +269,7 @@ export {
|
||||
LayPageHeader,
|
||||
LayCascader,
|
||||
LayAffix,
|
||||
LaySpace,
|
||||
install,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user