从零搭建Vue3.0组件之布局组件

一.Row、Col组件

import { computed, defineComponent, h } from "vue";
export default defineComponent({
    name: 'ZRow',
    props: {
        tag: {
            type: String,
            default: 'div'
        }
    },
    setup(props, { slots }) {
        const classs = computed(() => [
            'z-row'
        ])
        return () => h(props.tag, {
            class: classs.value
        }, slots.default?.())
    }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { computed, defineComponent, h } from "vue"
export default defineComponent({
    name: 'ZCol',
    props: {
        tag: {
            type: String,
            default: 'div',
        }
    },
    setup(props, { slots }) {
        const classs = computed(() => [
            'z-col'
        ])
        return () => h(props.tag, {
            class: classs.value
        }, slots.default?.())
    }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

二.设置列宽

row.scss

@import "common/var";
@import "mixins/mixins";
@include b(row){
    display: flex;
    flex-wrap: wrap;
}
1
2
3
4
5
6

col.scss

import { computed, defineComponent, h } from "vue"
export default defineComponent({
    name: 'ZCol',
    props: {
        tag: {
            type: String,
            default: 'div'
        },
        span: {
            type: Number,
            default: 24
        },
        offset: {
            type: Number,
            default: 0,
        }
    },
    setup(props, { slots }) {
        const classs = computed(() => {
            const ret: string[] = [];
            const pos = ['span', 'offset'] as const;
            pos.forEach(item => {
                const size = props[item];
                if (typeof size == 'number' && size > 0) {
                    ret.push(`z-col-${item}-${props[item]}`);
                }
            })
            return [
                'z-col',
                ...ret
            ]
        })
        return () => h(props.tag, {
            class: classs.value
        }, slots.default?.())
    }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@import './common/var.scss';
@import './mixins/mixins.scss';

@for $i from 0 through 24 {
    .#{$namespace}-col-span-#{$i} {
        max-width: (1 / 24 * $i * 100) * 1%;
        flex: (1/24 * $i * 100) * 1%;
    }
    .#{$namespace}-col-offset-#{$i} {
        margin-left: (1 / 24 * $i * 100) * 1%;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

三.设置行信息

将Row组件中的gutter属性暴露出去,在Col组件中注入属性

provide('ZRow',props.gutter);
const style = computed(() => {
    const ret = {
        marginLeft: '',
        marginRight: '',
    }
    if (props.gutter) { // 放大宽度
        ret.marginLeft = `-${props.gutter / 2}px`
        ret.marginRight = ret.marginLeft
    }
    return ret
})
1
2
3
4
5
6
7
8
9
10
11
12
setup(props, { slots }) {
    const gutter = inject('ZRow', 0)
    const style = computed(() => { // 设置间距
        if (gutter) {
            return {
                paddingLeft: gutter / 2 + 'px',
                paddingRight: gutter / 2 + 'px'
            }
        }
        return {}
    })
    return () => h(props.tag, {
        class: classs.value,
        style: style.value
    }, slots.default?.())
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[class*="#{$namespace}-col-"] {
    box-sizing: border-box;
}
1
2
3

保证padding不影响宽度

四.响应式

$--sm: 768px !default;
$--md: 992px !default;
$--lg: 1200px !default;
$--xl: 1920px !default;

$--breakpoints: (
  'xs' : (max-width: $--sm - 1),
  'sm' : (min-width: $--sm),
  'md' : (min-width: $--md),
  'lg' : (min-width: $--lg),
  'xl' : (min-width: $--xl)
);

@mixin res($key, $map: $--breakpoints) {
    // 循环断点Map,如果存在则返回
    @if map-has-key($map, $key) {
        @media only screen and #{inspect(map-get($map, $key))} {
            @content;
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

针对不同尺寸生成对应样式结构

@include res(xs) {
  @for $i from 0 through 24 {
    .#{$namespace}-col-xs-#{$i} {
      max-width: (1 / 24 * $i * 100) * 1%;
      flex: 0 0 (1 / 24 * $i * 100) * 1%;
    }
    .#{$namespace}-col-xs-offset-#{$i} {
      margin-left: (1 / 24 * $i * 100) * 1%;
    }
  }
}
@include res(sm) {
  @for $i from 0 through 24 {
    .#{$namespace}-col-sm-#{$i} {
      max-width: (1 / 24 * $i * 100) * 1%;
      flex: 0 0 (1 / 24 * $i * 100) * 1%;
    }
    .#{$namespace}-col-sm-offset-#{$i} {
      margin-left: (1 / 24 * $i * 100) * 1%;
    }
  }
}
@include res(md) {
  @for $i from 0 through 24 {
    .#{$namespace}-col-md-#{$i} {
      max-width: (1 / 24 * $i * 100) * 1%;
      flex: 0 0 (1 / 24 * $i * 100) * 1%;
    }

    .#{$namespace}-col-md-offset-#{$i} {
      margin-left: (1 / 24 * $i * 100) * 1%;
    }
  }
}

@include res(lg) {
  @for $i from 0 through 24 {
    .#{$namespace}-col-lg-#{$i} {
      max-width: (1 / 24 * $i * 100) * 1%;
      flex: 0 0 (1 / 24 * $i * 100) * 1%;
    }
    .#{$namespace}-col-lg-offset-#{$i} {
      margin-left: (1 / 24 * $i * 100) * 1%;
    }
  }
}
@include res(xl) {
  @for $i from 0 through 24 {
    .#{$namespace}-col-xl-#{$i} {
      max-width: (1 / 24 * $i * 100) * 1%;
      flex: 0 0 (1 / 24 * $i * 100) * 1%;
    }
    .#{$namespace}-col-xl-offset-#{$i} {
      margin-left: (1 / 24 * $i * 100) * 1%;
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

col.ts

const sizes = ['xs', 'sm', 'md', 'lg', 'xl'] as const
sizes.forEach(size => {
    if (typeof props[size] === 'number') {
    	ret.push(`z-col-${size}-${props[size]}`)
    }
})
1
2
3
4
5
6

根据用户设置的属性

五.对其方式

row.ts

const classs = computed(() => [
    'z-row',
    props.justify !== 'start' ? `is-justify-${props.justify}` : '',
])
1
2
3
4
@include b(row) {
    display: flex;
    flex-wrap: wrap;
    @include when(justify-center) {
        justify-content: center;
    }
    @include when(justify-end) {
        justify-content: flex-end;
    }

    @include when(justify-space-between) {
        justify-content: space-between;
    }

    @include when(justify-space-around) {
        justify-content: space-around;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

设置flex布局对其方式即可