# 了解一下常见布局?

# 表单复杂布局

如果要你用 CSS 框架(ElementUI、Ant Design Vue 等等)实现以下效果,你会怎么实现?

image-20210906114601031

<!-- 代码有缩减,目的是看懂 -->
<template>
  <!-- 第一行普通布局 -->
  <a-form-model
    layout="horizontal"
    :label-col="{ span: 4 }"
    :wrapper-col="{ span: 10 }"
  >
    <a-form-model-item label="表描述" prop="tableDesc"></a-form-model-item>

    <!-- 第二行内嵌其它表单布局 -->
    <a-form-model-item
      :label-col="{ span: 4 }"
      :wrapper-col="{ span: 18 }"
      label="业务及层级"
    >
      <a-row :gutter="10">
        <a-col :span="6">
          <a-form-model-item prop="businessId"></a-form-model-item>
        </a-col>
        <a-col :span="18">
          <a-form-model-item prop="level"></a-form-model-item>
        </a-col>
      </a-row>
    </a-form-model-item>

    <!-- 第三行内嵌二级表单布局 -->
    <a-form-model-item label="主题域&amp;主题">
      <a-row :gutter="10">
        <a-col :span="12">
          <a-form-model-item prop="primaryClassId" required></a-form-model-item>
        </a-col>
        <a-col :span="12">
          <a-form-model-item
            prop="secondaryClassId"
            required
          ></a-form-model-item>
        </a-col>
      </a-row>
    </a-form-model-item>

    <!-- 第四行同行两个同类型表单布局 -->
    <a-row :gutter="5">
      <a-col :span="8">
        <a-form-model-item
          label="业务负责人"
          prop="bizPrincipal"
          :label-col="{ span: 12 }"
          :wrapper-col="{ span: 10 }"
        ></a-form-model-item>
      </a-col>
      <a-col :span="8">
        <a-form-model-item
          label="技术负责人"
          prop="techPrincipal"
          :label-col="{ span: 8 }"
          :wrapper-col="{ span: 10 }"
          required
        ></a-form-model-item>
      </a-col>
    </a-row>
  </a-form-model>
</template>
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
58
59
60
61
62
63

这里面的重点是要理解a-form-model-item的作用:它实际上起到布局和校验的作用,这里我们只考虑布局

实现第三行布局时(一个标签,两个联动选择框),我们可以用一个只带label属性的a-form-model-item去跟上面的表单布局适应,里面实际的渲染空间只有wrapper-col的大小,在里面再使用一个a-row来进行栅格布局就可以轻松达到每个输入框各占 50%

实现第四行布局时(两个标签,两个选择框),有两种写法

  1. 第一种类似第三行的布局
  2. 第二种直接用栅格布局,但是要注意两个a-col加起来要等于label-col+wrapper-col的大小(如果a-row加了gutter,则两个a-col加起来要略大于label-col+wrapper-col的大小),之后在里面再使用a-form-model-itemlabel-colwrapper-col进行适当调整

# 网格自适应响应布局

<style>
  /* content是外面的大盒子 */
  .content {
    display: grid;
    grid-gap: 10px; /* 网格间距 */
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); /* 关键代码 */
    grid-template-rows: auto;
  }
</style>
1
2
3
4
5
6
7
8
9

解释一下关键代码grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));

grid-template-columns是设置网格列宽的

repeat是一个函数,结合auto-fit使用的话,表明每个列都是自适应的

minmax(200px,1fr)表示列最小宽度是 200px,1fr表示每列最大宽度自动分配等额剩余空间


# 左固定,右 10%,中间自适应

# float 实现

<style>
  body {
    margin: 0;
    padding: 0;
  }

  /* 浮动 */
  .float-wrapper {
    width: 100%;
    height: 500px;
  }

  .float-left {
    float: left;
    width: 200px;
    height: 100%;
    background-color: #000;
  }

  .float-right {
    float: right;
    width: 10%;
    height: 100%;
    background-color: #000;
  }

  .float-center {
    margin: 0 10% 0 200px;
    height: 100%;
    background-color: yellow;
  }
</style>

<body>
  <!-- 左200px 右10% 中间撑满 -->
  <!-- 浮动  -->
  <div class="float-wrapper">
    <div class="float-left"></div>
    <div class="float-right"></div>
    <div class="float-center"></div>
  </div>
</body>
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

# flex 实现

<style>
  body {
    margin: 0;
    padding: 0;
  }

  /* flex */
  .flex-wrapper {
    margin-top: 40px;
    width: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 500px;
    border: 1px solid #000;
  }

  .flex-left {
    width: 200px;
    background-color: green;
    height: 100%;
  }

  .flex-center {
    flex: 1;
    background-color: yellow;
    height: 100%;
  }

  .flex-right {
    width: 10%;
    background-color: red;
    height: 100%;
  }
</style>

<body>
  <!-- 左200px 右10% 中间撑满 -->
  <!-- 浮动  -->
  <div class="flex-wrapper">
    <div class="flex-left"></div>
    <div class="flex-right"></div>
    <div class="flex-center"></div>
  </div>
</body>
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

# grid 实现

<style>
  body {
    margin: 0;
    padding: 0;
  }

  /* grid */
  .grid-wrapper {
    margin-top: 40px;
    width: 100%;
    height: 500px;
    display: grid;
    grid-template-columns: 200px 1fr 10%;
  }

  .grid-left {
    background-color: green;
    height: 100%;
  }

  .grid-center {
    background-color: yellow;
    height: 100%;
  }

  .grid-right {
    background-color: red;
    height: 100%;
  }
</style>

<body>
  <!-- 左200px 右10% 中间撑满 -->
  <!-- grid -->
  <div class="grid-wrapper">
    <div class="grid-left"></div>
    <div class="grid-center"></div>
    <div class="grid-right"></div>
  </div>
</body>
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

# 收缩展开布局

<template>
  <div class="radio-content">
    <a-radio-group
      class="radio-group"
      name="radioGroup"
      :default-value="defaultVal"
      button-style="solid"
      v-model:value="subValue"
      @change="(e) => $emit('update:value', e.target.value)"
    >
      <div class="label-wrapper" v-for="item in renderedOps" :key="item.val">
        <a-radio-button :value="item.val" class="radio-btn">{{
          item.label
        }}</a-radio-button>
      </div>
      <div class="btn-content">
        <a-button v-if="showMore" type="link" @click="expendOps" class="btn"
          >更多</a-button
        >
        <a-button v-if="showShrink" type="link" @click="shrinkOps" class="btn"
          >收起</a-button
        >
      </div>
    </a-radio-group>
  </div>
</template>
<style lang="less" scoped>
.radio-content {
  flex-grow: 1;
  .radio-group {
    display: flex;
    justify-content: flex-start;
    align-items: center;
    flex-wrap: wrap; /*关键代码*/
    .label-wrapper {
      flex: 0 0 25%; /*关键代码*/
      text-align: center;
      margin-bottom: 10px;
    }
    .btn-content {
      width: 25%;
      flex-grow: 1; /*关键代码*/
      text-align: right; /*关键代码*/
      margin-bottom: 10px;
      .btn {
        // float: right;
      }
    }
  }
}
/deep/.ant-radio-button-wrapper {
  border: none;
  border-radius: 4px;
  // margin: 5px;
  padding: 0 10px;
}
/deep/.ant-radio-button-wrapper::before {
  content: none;
}
</style>
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
58
59
60

思路:先不管选项内容,我们要十分清楚实现什么样的布局,重要是后面的多个radio的布局,由于一行固定放四个(包括按钮),我们将一行均分成 4 个方块,每个方块基础宽度(flex-basis)占25%,不管里面放什么内容,不能伸缩放大,也就是设置flex: 0 0 25%

单独处理button按钮,我们可以看到它是放在每一行的最右边,如果刚好是下一行也是如此,假设刚好有 5 个radio,这时候应该是 4 个排在第一行,剩下 1 个排在第二行,后面剩下75%的宽度如何放置按钮呢,我们可以将按钮的flex-grow设置为 1,也就是吸收剩余空间,这样按钮就占据75%的宽度的,此时按钮是默认排在第 5 个radio的后面,我们需要将按钮移到最右边,怎么办呢?很简单,设置button的父divtext-alignright既可

布局关键点:

  • 将操作按钮当成radio的一部分,放到options最后面

  • 将每个radio选项和button按钮用div包裹,避免宽度影响原本的radio和按钮大小

  • 父容器设置display:flex;flex-warp:wrap;

  • radiodiv设置flex: 0 0 25%;

  • buttondiv设置flex-grow: 1;width:25%;text-align: right;

最近更新: 4 小时前