feat(Row): gutter support vertical space (#12439)

Co-authored-by: inottn <inottn@outlook.com>
This commit is contained in:
cc heart 2023-11-18 21:16:17 +08:00 committed by GitHub
parent a75a458062
commit 632ff0be31
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 234 additions and 14 deletions

View File

@ -4,6 +4,7 @@ import {
createNamespace,
makeNumericProp,
makeStringProp,
extend,
} from '../utils';
import { useParent } from '@vant/use';
import { ROW_KEY } from '../row/Row';
@ -31,15 +32,21 @@ export default defineComponent({
return;
}
const { spaces } = parent;
const { spaces, verticalSpaces } = parent;
let styles = {};
if (spaces && spaces.value && spaces.value[index.value]) {
const { left, right } = spaces.value[index.value];
return {
styles = {
paddingLeft: left ? `${left}px` : null,
paddingRight: right ? `${right}px` : null,
};
}
const { bottom } = verticalSpaces.value[index.value] || {};
return extend(styles, {
marginBottom: bottom ? `${bottom}px` : null,
});
});
return () => {

View File

@ -53,6 +53,20 @@ Set grid spacing using `gutter` attribute. The default value is 0.
</van-row>
```
### Vertical Spacing
If you want to set the vertical spacing, you can set `[horizontal, vertical]` as an array.
```html
<!-- set the vertical spacing -->
<van-row :gutter="[20, 20]">
<van-col span="12">span: 12</van-col>
<van-col span="12">span: 12</van-col>
<van-col span="12">span: 12</van-col>
<van-col span="12">span: 12</van-col>
</van-row>
```
### Justify Content
```html
@ -87,7 +101,7 @@ Set grid spacing using `gutter` attribute. The default value is 0.
| Attribute | Description | Type | Default |
| --- | --- | --- | --- |
| gutter | Grid spacingpx | _number \| string_ | - |
| gutter | Grid spacingpx | _number \| string \| Array_ | - |
| tag | Custom element tag | _string_ | `div` |
| justify | Flex main axis, can be set to end/center/space-around/space-between | _string_ | `start` |
| align | Flex cross axis, be set to center/bottom | _string_ | `top` |

View File

@ -52,6 +52,20 @@ Layout 组件提供了 `24列栅格`,通过在 `Col` 上添加 `span` 属性
</van-row>
```
### 垂直间距
如果需要设置垂直间距,可以使用数组形式设置 `[水平间距, 垂直间距]`
```html
<!-- 设置垂直间距 -->
<van-row :gutter="[20, 20]">
<van-col span="12">span: 12</van-col>
<van-col span="12">span: 12</van-col>
<van-col span="12">span: 12</van-col>
<van-col span="12">span: 12</van-col>
</van-row>
```
### 对齐方式
通过 `justify` 属性可以设置主轴上内容的对齐方式,等价于 flex 布局中的 `justify-content` 属性。
@ -92,7 +106,7 @@ Layout 组件提供了 `24列栅格`,通过在 `Col` 上添加 `span` 属性
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| gutter | 列元素之间的间距(单位为 px | _number \| string_ | - |
| gutter | 列元素之间的间距(单位为 px | _number \| string \| Array_ | - |
| tag | 自定义元素标签 | _string_ | `div` |
| justify | 主轴对齐方式,可选值为 `end` `center` <br> `space-around` `space-between` | _string_ | `start` |
| align | 交叉轴对齐方式,可选值为 `center` `bottom` | _string_ | `top` |

View File

@ -7,10 +7,12 @@ const t = useTranslate({
'zh-CN': {
title2: '在列元素之间增加间距',
justify: '对齐方式',
vertical: '垂直间距',
},
'en-US': {
title2: 'Column Spacing',
justify: 'Justify Content',
vertical: 'Vertical Spacing',
},
});
</script>
@ -41,6 +43,17 @@ const t = useTranslate({
</van-row>
</demo-block>
<demo-block :title="t('vertical')">
<div class="demo-vertical-space">
<van-row :gutter="[20, 20]">
<van-col span="12">span: 12</van-col>
<van-col span="12">span: 12</van-col>
<van-col span="12">span: 12</van-col>
<van-col span="12">span: 12</van-col>
</van-row>
</div>
</demo-block>
<demo-block :title="t('justify')">
<van-row justify="center">
<van-col span="6">span: 6</van-col>
@ -95,4 +108,10 @@ const t = useTranslate({
}
}
}
.demo-vertical-space {
.van-col {
margin-bottom: 0;
}
}
</style>

View File

@ -83,6 +83,42 @@ exports[`should render demo and match snapshot 1`] = `
</div>
</div>
</div>
<div>
<!--[-->
<div class="demo-vertical-space">
<div class="van-row">
<!--[-->
<div
style
class="van-col van-col--12"
>
<!--[-->
span: 12
</div>
<div
style
class="van-col van-col--12"
>
<!--[-->
span: 12
</div>
<div
style
class="van-col van-col--12"
>
<!--[-->
span: 12
</div>
<div
style
class="van-col van-col--12"
>
<!--[-->
span: 12
</div>
</div>
</div>
</div>
<div>
<!--[-->
<div class="van-row van-row--justify-center">

View File

@ -49,6 +49,36 @@ exports[`should render demo and match snapshot 1`] = `
</div>
</div>
</div>
<div>
<div class="demo-vertical-space">
<div class="van-row">
<div
class="van-col van-col--12"
style="padding-right: 10px; margin-bottom: 20px;"
>
span: 12
</div>
<div
style="padding-left: 10px; margin-bottom: 20px;"
class="van-col van-col--12"
>
span: 12
</div>
<div
class="van-col van-col--12"
style="padding-right: 10px;"
>
span: 12
</div>
<div
style="padding-left: 10px;"
class="van-col van-col--12"
>
span: 12
</div>
</div>
</div>
</div>
<div>
<div class="van-row van-row--justify-center">
<div class="van-col van-col--6">

View File

@ -1,6 +1,7 @@
import { Col } from '..';
import { Row } from '../../row';
import { mount } from '../../../test';
import { nextTick } from 'vue';
test('should render Col correctly', () => {
const wrapper = mount(Col, {
@ -41,3 +42,77 @@ test('should render gutter correctly', () => {
expect(wrapper.html()).toMatchSnapshot();
});
test('should render vertical space when gutter is an array and provide the second parameter', async () => {
const wrapper = mount({
render: () => (
<Row gutter={[0, 20]}>
<Col span="12">12</Col>
<Col span="12">12</Col>
<Col span="12">12</Col>
<Col span="12">12</Col>
</Row>
),
});
const fields = wrapper.findAll('.van-col');
await nextTick();
expect(fields[0].style.marginBottom).toEqual('20px');
expect(fields[1].style.marginBottom).toEqual('20px');
expect(fields[2].style.marginBottom).toBeFalsy();
expect(fields[3].style.marginBottom).toBeFalsy();
});
test('should not render vertical space when gutter is an array and provide the second parameter as negative number', async () => {
const wrapper = mount({
render: () => (
<Row gutter={[16, -16]}>
<Col span="12">12</Col>
<Col span="12">12</Col>
<Col span="12">12</Col>
<Col span="12">12</Col>
</Row>
),
});
const fields = wrapper.findAll('.van-col');
await nextTick();
fields.forEach((field) => {
expect(field.style.marginBottom).toBeFalsy();
});
});
test('should not render space when gutter is an empty array', async () => {
const wrapper = mount({
render: () => (
<Row gutter={[]}>
<Col span="12">12</Col>
<Col span="12">12</Col>
<Col span="12">12</Col>
<Col span="12">12</Col>
</Row>
),
});
const field = wrapper.findAll('.van-col')[0];
await nextTick();
expect(field.style.paddingRight).toBeFalsy();
expect(field.style.marginBottom).toBeFalsy();
});
test('should not render vertical space when gutter is an array and provide the second parameter as invalid number', async () => {
const wrapper = mount({
render: () => (
<Row gutter={[0, 'invalid']}>
<Col span="12">12</Col>
<Col span="12">12</Col>
<Col span="12">12</Col>
<Col span="12">12</Col>
</Row>
),
});
const field = wrapper.findAll('.van-col')[0];
await nextTick();
expect(field.style.marginBottom).toBeFalsy();
});

View File

@ -6,20 +6,17 @@ import {
type InjectionKey,
type ExtractPropTypes,
} from 'vue';
import {
truthProp,
makeStringProp,
makeNumericProp,
createNamespace,
} from '../utils';
import { truthProp, makeStringProp, createNamespace } from '../utils';
import { useChildren } from '@vant/use';
const [name, bem] = createNamespace('row');
export type RowSpaces = { left?: number; right: number }[];
export type VerticalSpaces = { bottom?: number }[];
export type RowProvide = {
spaces: ComputedRef<RowSpaces>;
verticalSpaces: ComputedRef<VerticalSpaces>;
};
export const ROW_KEY: InjectionKey<RowProvide> = Symbol(name);
@ -37,7 +34,12 @@ export const rowProps = {
tag: makeStringProp<keyof HTMLElementTagNameMap>('div'),
wrap: truthProp,
align: String as PropType<RowAlign>,
gutter: makeNumericProp(0),
gutter: {
type: [String, Number, Array] as PropType<
string | number | (string | number)[]
>,
default: 0,
},
justify: String as PropType<RowJustify>,
};
@ -70,7 +72,12 @@ export default defineComponent({
});
const spaces = computed(() => {
const gutter = Number(props.gutter);
let gutter = 0;
if (Array.isArray(props.gutter)) {
gutter = Number(props.gutter[0]) || 0;
} else {
gutter = Number(props.gutter);
}
const spaces: RowSpaces = [];
if (!gutter) {
@ -94,7 +101,25 @@ export default defineComponent({
return spaces;
});
linkChildren({ spaces });
const verticalSpaces = computed(() => {
const { gutter } = props;
const spaces: VerticalSpaces = [];
if (Array.isArray(gutter) && gutter.length > 1) {
const bottom = Number(gutter[1]) || 0;
if (bottom <= 0) {
return spaces;
}
groups.value.forEach((group, index) => {
if (index === groups.value.length - 1) return;
group.forEach(() => {
spaces.push({ bottom });
});
});
}
return spaces;
});
linkChildren({ spaces, verticalSpaces });
return () => {
const { tag, wrap, align, justify } = props;