可自定义设置以下属性:
- 区域总宽度(width),类型:string|number,默认 ‘auto’
- 垂直排列方式(align),类型:‘stretch’|‘start’|‘end’|‘center’|‘baseline’,默认 ‘start’
- 间距方向(direction),类型:‘horizontal’|‘vertical’,默认: ‘horizontal’
- 间距大小(size),数组时表示: [水平间距, 垂直间距],类型:number|number[]|‘small’|‘middle’|‘large’,默认 ‘small’
- 是否自动换行(wrap),仅在 horizontal 时有效,类型:boolean,默认 true
效果如下图:在线预览
创建间距组件Space.vue
<script setup lang="ts">
import { computed } from 'vue'
interface Props {
width?: string|number // 区域总宽度
align?: 'stretch'|'start'|'end'|'center'|'baseline' // 垂直排列方式
direction?: 'horizontal'|'vertical' // 间距方向
size?: number|number[]|'small'|'middle'|'large' // 间距大小,数组时表示: [水平间距, 垂直间距]
wrap?: boolean // 是否自动换行,仅在 horizontal 时有效
}
const props = withDefaults(defineProps<Props>(), {
width: 'auto',
align: 'start',
direction: 'horizontal',
size: 'small',
wrap: true
})
const spaceWidth = computed(() => {
if (typeof props.width === 'number') {
return props.width + 'px'
}
return props.width
})
const gap = computed(() => {
if (typeof props.size === 'number') {
return props.size + 'px'
}
if (Array.isArray(props.size)) {
return props.size[1] + 'px ' + props.size[0] + 'px '
}
if (['small', 'middle', 'large'].includes(props.size)) {
const gapMap = {
small: '8px',
middle: '16px',
large: '24px'
}
return gapMap[props.size]
}
})
</script>
<template>
<div
class="m-space"
:class="[`${direction} ${align}`, {wrap: wrap}]"
:style="`width: ${spaceWidth}; gap: ${gap}; margin-bottom: -${Array.isArray(props.size) && wrap ? props.size[1] : 0}px;`">
<slot></slot>
</div>
</template>
<style lang="less" scoped>
.m-space {
display: inline-flex;
font-size: 14px;
color: rgba(0, 0, 0, .88);
transition: all .3s;
}
.horizontal {
flex-direction: row;
}
.vertical {
flex-direction: column;
}
.stretch {
align-items: stretch;
}
.start {
align-items: flex-start;
}
.end {
align-items: flex-end;
}
.center {
align-items: center;
}
.baseline {
align-items: baseline;
}
.wrap {
flex-wrap: wrap;
}
</style>
在要使用的页面引入
其中引入使用了 Vue3单选(Radio)、Vue3按钮(Button)、Vue3卡片(Card)
<script setup lang="ts">
import Space from './Space.vue'
import { ref } from 'vue'
const sizeNum = ref(8)
const options = ref([
{
label: 'Small',
value: 'small'
},
{
label: 'Middle',
value: 'middle',
},
{
label: 'Large',
value: 'large'
}
])
const size = ref('small')
</script>
<template>
<div>
<h1>Space 间距</h1>
<h2 class="mt30 mb10">基本使用</h2>
<Space align="center">
Space
<Button type="primary">Button</Button>
<Popconfirm title="Are you sure delete this task?" ok-text="Yes" cancel-text="No">
<Button>Confirm</Button>
</Popconfirm>
</Space>
<h2 class="mt30 mb10">自定义间距</h2>
<Slider v-model:value="sizeNum" />
<br />
<br />
<Space :size="sizeNum">
<Button type="primary">Primary</Button>
<Button>Default</Button>
<Button type="dashed">Dashed</Button>
<Button type="link">Link</Button>
</Space>
<h2 class="mt30 mb10">预设间距</h2>
<Radio :options="options" v-model:value="size" />
<br/><br/>
<Space :size="size">
<Button type="primary">Primary</Button>
<Button>Default</Button>
<Button type="dashed">Dashed</Button>
<Button type="link">Link</Button>
</Space>
<h2 class="mt30 mb10">垂直间距</h2>
<Space direction="vertical">
<Card title="Card" style="width: 300px">
<p>Card content</p>
<p>Card content</p>
</Card>
<Card title="Card" style="width: 300px">
<p>Card content</p>
<p>Card content</p>
</Card>
</Space>
<h2 class="mt30 mb10">对齐</h2>
<div class="space-align-container">
<div class="space-align-block">
<Space align="center">
center
<Button type="primary">Primary</Button>
<span class="mock-block">Block</span>
</Space>
</div>
<div class="space-align-block">
<Space align="start">
start
<Button type="primary">Primary</Button>
<span class="mock-block">Block</span>
</Space>
</div>
<div class="space-align-block">
<Space align="end">
end
<Button type="primary">Primary</Button>
<span class="mock-block">Block</span>
</Space>
</div>
<div class="space-align-block">
<Space align="baseline">
baseline
<Button type="primary">Primary</Button>
<span class="mock-block">Block</span>
</Space>
</div>
</div>
<h2 class="mt30 mb10">自动换行</h2>
<Space :size="[8, 16]" style="width: 600px;">
<template v-for="n in 10" :key="n">
<Button>Button</Button>
</template>
</Space>
</div>
</template>
<style lang="less" scoped>
.space-align-container {
display: flex;
align-items: flex-start;
flex-wrap: wrap;
}
.space-align-block {
margin: 8px 4px;
border: 1px solid #40a9ff;
padding: 4px;
flex: none;
}
.space-align-block .mock-block {
display: inline-block;
padding: 32px 8px 16px;
background: rgba(150, 150, 150, 0.2);
}
</style>