Element UI 中表单使用栅格实现多行多列布局会错位的问题

业务中经常会遇到多行多列展示的表单需求,所以我们会搭配着栅格组件来实现。利用栅格化布局 span 超过 24 会自动折行的功能。

<el-form ref="form" :model="form" label-width="auto">
  <el-row :gutter="10">
    <el-col :span="12">
      <el-form-item label="字段A">
        <el-input v-model="form.a" placeholder="请输入"></el-input>
      </el-form-item>
    </el-col>
    <el-col :span='12'>
      <el-form-item label="字段B">
        <el-input v-model="form.b" placeholder="请输入"></el-input>
      </el-form-item>
    </el-col>
  </el-row>
</el-form>

如果这样组合使用的同学,肯定会遇到过表单项错位的问题。因为 Element UI 是栅格组件默认是使用的 float 布局的,所以如果你的 <el-form-item> 元素高度不一致的话,就会出现下边截图中布局错位的问题。

表单错位预览

字段C项并没有正确出现在字段A项的正下方,而是错开一列出现在了字段B的下方。

简单实现一下会出现问题的模板结构:

<template>
  <el-form ref="form" :model="form" label-width="auto">
    <el-row :gutter="10">
      <el-col :span="12">
        <el-form-item label="字段A">
          <el-input v-model="form.a" placeholder="请输入"></el-input>
        </el-form-item>
      </el-col>
      <el-col :span='12'>
        <el-form-item label="字段B">
          <el-radio-group v-model="form.b">
            <el-radio label="选项1"></el-radio>
            <el-radio label="选项2"></el-radio>
          </el-radio-group>
        </el-form-item>
      </el-col>
      <el-col :span='12'>
        <el-form-item label="字段C">
          <el-input v-model="form.c" placeholder="请输入"></el-input>
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="字段D">
          <el-input v-model="form.d" placeholder="请输入"></el-input>
        </el-form-item>
      </el-col>
    </el-row>
    <el-form-item>
      <el-row type="flex" justify="end">
        <el-button type="primary" @click="onSubmit">提交</el-button>
        <el-button>取消</el-button>
      <el-row>
    </el-form-item>
  </el-form>
</template>

可以看到字段B这一项,我使用了和其他项都不同的 <el-radio> 组件。所以字段B这一项的高度就会是比较“矮”,它比前一列字段A项的高度少了 1px
那么在使用 float 布局左对齐的时候,就会因为前置元素高度问题导致元素错位的情况。

错位原因示意图:

错位原因示意图

所以是不是只需要我们<el-form-item> 的高度统一就可以了?比如说简单覆盖一下原本表单组件的内置样式:

.el-form-item__content {
  line-height:45px; /* 原本是 40px */
  position:relative;
  font-size:14px
}

可以是可以,但如果内容物并不是使用的 EleUI 提供的表单组件,而是一些客制化内容还是会有问题。


所以如果我们的表单是固定了每行几列的话,在写模板的时候麻烦一些,每一行都创建一个 <el-row> 来包裹内容物那么就没问题了。现在网络上大部分解决方案也是让你这样操作,就不需要我们去修改表单组件的内置样式了。

<template>
  <el-form ref="form" :model="form" label-width="auto">
    <!-- 第一行 -->
    <el-row :gutter="10">
      <el-col :span="12">
        <el-form-item label="字段A">
          <el-input v-model="form.a" placeholder="请输入"></el-input>
        </el-form-item>
      </el-col>
      <el-col :span='12'>
        <el-form-item label="字段B">
          <el-radio-group v-model="form.b">
            <el-radio label="选项1"></el-radio>
            <el-radio label="选项2"></el-radio>
          </el-radio-group>
        </el-form-item>
      </el-col>
    </el-row>
    <!-- 第二行 -->
    <el-row :gutter="10">
      <el-col :span='12'>
        <el-form-item label="字段C">
          <el-input v-model="form.c" placeholder="请输入"></el-input>
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="字段D">
          <el-input v-model="form.d" placeholder="请输入"></el-input>
        </el-form-item>
      </el-col>
    </el-row>
  </el-form>
</template>

但是我们总是会遇到表单需要动态布局的场合对吧?比如说适配小屏幕设备,和表单项会按照权限判断来决定是否显示的情况。那么应该如何修改呢?

其实也很简单,通过给 <el-row> 设置 type="flex",将其设置为 flex 布局,但是栅格组件的 flex 模式下是不允许内容物折行的,所以我们还需要手动给 <el-row> 添加上 flex-wrap:wrap 的样式允许 flex 元素换行:

<template>
  <el-form ref="form" :model="form" label-width="auto">
    <el-row type="flex" style="flex-wrap:wrap" :gutter="10">
      <el-col :span="12">
        <el-form-item label="字段A">
          <el-input v-model="form.a" placeholder="请输入"></el-input>
        </el-form-item>
      </el-col>
      <el-col :span='12'>
        <el-form-item label="字段B">
          <el-radio-group v-model="form.b">
            <el-radio label="选项1"></el-radio>
            <el-radio label="选项2"></el-radio>
          </el-radio-group>
        </el-form-item>
      </el-col>
      <el-col :span='12'>
        <el-form-item label="字段C">
          <el-input v-model="form.c" placeholder="请输入"></el-input>
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="字段D">
          <el-input v-model="form.d" placeholder="请输入"></el-input>
        </el-form-item>
      </el-col>
    </el-row>
  </el-form>
</template>

这样就没有问题了。