(component): [space]新增 space 组件

This commit is contained in:
sight
2022-08-27 08:02:54 +08:00
parent c235cbb1f1
commit cf0b74820e
8 changed files with 464 additions and 0 deletions

View 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);
};
},
});

View 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;
}
}

View 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;

View 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>

View File

@@ -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,
};