基于element-ui进行组件的二次封装

组件文档

1.FormItem

引用方式

import FormItem from "@/components/FormItem";

参数列表

参数名说明类型可选值默认值
type表单元素类型string
prop表单字段名称String-
value表单双向绑定的值String, Number, Boolean, Array, Object
label表单lebelString
placeholder表单元素中的提示语String
disabled表单元素是否禁用Booleanfalse
options表单元素type类型是select时需要传入该字段Array
width表单元素宽度,注意要带上px单位String
suffix输入框尾部内容,输入框尾部内容,只对 type="text" 有效
clearable表单元素是否可以清空Booleantrue
filterableselect 是否可搜索Booleanfalse
activeTextswitch 打开时的文字描述String
inactiveTextswitch 关闭时的文字描述String
size输入框尺寸,只在 type!="textarea" 时有效Stringmedium / small / mini

注意:表单需要的属性非常多,上面参数列表没必要一一穷尽,我们可以使用v-bind="$attrs"将props中没有定义的属性,透传到表单元素上。示例

  <el-input
    v-if="type === 'input'"
    :size="size || 'mini'"
    v-model.trim="localValue"
    :placeholder="placeholder || '请输入内容'"
    :clearable="clearable"
    v-bind="$attrs"
    :style="[width ? { width: width } : '']"
  >
    <span v-if="suffix" slot="suffix">{{ suffix }}</span>
  </el-input>

支持渲染的标签

  • Input
  • InputNumber
  • Select
  • DatePicker (date,month,daterange)
  • Switch

代码示例见FilterForm

2.FilterForm 过滤表单

引用方式

import FilterForm from "@/components/FilterForm";

参数列表

参数名说明类型可选值默认值
formConfig过滤条件表单项配置Array-[]
formData表单双向绑定的数据Object-{}
inline行内表单模式Booleantrue/falsefalse
labelWidth表单域标签的宽度,例如 '50px'。作为 Form 直接子元素的 form-item 会继承该值。支持 auto。String-"80px"

方法

方法名说明参数
handleSubmit点击查询按钮调用该方法,触发父组件身上的submit事件,把formData传出去-
handleReset点击重置按钮调用该方法 ,实际调用el-form自身的resetFields对整个表单进行重置,将所有字段值重置为初始值并移除校验结果 。触发父组件身上的submit事件,把formData传出去-

Slots插槽

名称说明
formExOperation过滤表单操作按钮,默认只配置了查询和重置,如果想要增加像导出等操作,可以通过formExOperation配置

注意:如果一个组件的插槽过多,我们可以通过另一个属性$lots,这个属性表示父组件传入的所有的插槽,是一个对象。键名对应着插槽名,键值是一个vnode数组,如下:

image.png

代码示例,父向子传递多个插槽,并传递了数据:

  <el-input ref="refInput" v-bind="$attrs">
    <template v-for="(_value, name) in $slots" #[name]="slotData">
      <slot :name="name" v-bind="slotData || {}" />
    </template>
  </el-input>

代码示例见FilterTablePagination

3.BasicTable 基于el-table对表格组件进行二次封装

参数列表

参数名说明类型可选值默认值
tableData表格显示的数据Array-[]
columns表格的列数据Array-[]
loading表格数据加载中的loading效果Boolean-false
height设置height可以固定表头Number--
multipleSelection表格多选时需要传入此参数,会存放表格多选时选中的rowArray-[]

注意:表格需要的属性非常多,比如row-class-name可以设置表格行的隔行变色。上面参数列表没必要一一穷尽,我们可以使用v-bind="$attrs"将props中没有定义的属性,透传到el-table元素上。示例

    <el-table :data="tableData" ref="basicTableRef" style="width: 100%" :height="height" @selection-change="handleSelectionChange" v-loading="loading" v-bind="$attrs">
    </el-table>

如果组件又套了一层组件,如果需要透传el-table表格属性,这里要加上v-bind="tableProps",像FilterTablePagination中的组件使用BasicTable组件,代码示例如下:

    <basic-table :tableData="tableProps.tableData" :columns="tableProps.columns" :multipleSelection="tableProps.multipleSelection" v-bind="tableProps">
      <!-- 表格操作列 -->
      <template #tableOperation="{ row, column, $index }">
        <slot name="tableOperation" :row="row" :$index="$index" :column="column"></slot>
      </template>
    </basic-table>

方法

方法名说明参数
handleSelectionChange表格的events selection-change上绑定该方法 ,当选择项发生变化时会触发该事件。实际会触发父上的selectionChange把selection参数传出去selection。
clearAll点击清空时调用 ,实际调用el-table自身的clearSelection清空多选表格用户的选择,父要调用直接使用ref调用子组件身上的方法-

Slots插槽

名称说明
item.prop表格列prop,是一个动态插槽。如果某一列的内容需要自定义可以使用插槽,比如某一列的内容可以编辑
item.prop +"_header"表格列header,是一个动态插槽。如果某一列的表头需要自定义可以使用插槽,比如某一列的表头需要展示prop和相关图标

注意

1.如果需要对表格单元格内容进行格式化时需要给el-table-column添加formatter方法,此方法不能直接封装在slot插槽中。所以在封装中设置了2个列,根据column配置中是否传入custom字段进行区分。如果custom为true则使用自定义列,比如可以设置可编辑的单元格之类的。如果不传custom则使用普通列,列上配置formatter属性。代码如下:

  <el-table :data="tableData" ref="basicTableRef" style="width: 100%" border @selection-change="handleSelectionChange" v-loading="loading" :header-cell-class-name="getHeaderCellClassName || ''">
    <template v-for="(item,index) in columns">
      <el-table-column v-if="['index','selection'].includes(item.type)" :type="item.type" :key="index" :label="item.label" :align="item.align || 'center'" v-bind="item.attrs || {}" width="55" :selectable="item.selectable">
      </el-table-column>
      <!-- 自定义列模板 columns数组中item需要定义custom字段 -->
      <el-table-column v-else-if="item.custom" :width="item.width" v-bind="item.attrs || {}" :key="item.prop+'custom'" :show-overflow-tooltip='item.showOverflowTooltip || false'>
        <template slot="header" slot-scope="{$index,column}">
          <slot :name='item.prop +"_header"' :$index='$index' :column="column" :label="item.label">{{item.label}}</slot>
        </template>
        <template slot-scope="{$index,row,column}">
          <slot :name="item.prop" :$index='$index' :row="row" :column="{...column,...item}">
            {{row[item.prop]}}
          </slot>
        </template>
      </el-table-column>

      <el-table-column v-else :prop="item.prop" :label="item.label" :formatter="item.formatter" :width="item.width" v-bind="item.attrs || {}" :key="item.prop">
        <template slot="header" slot-scope="{$index,row,column}">
          <slot :name='item.prop +"_header"' :$index='$index' :column="column" :label="item.label">{{item.label}}</slot>
        </template>
      </el-table-column>
    </template>
  </el-table>

将formatter封装在插槽中,类似这样的column项会报错:

     {
          prop: 'status',
          label: '项目估值状态',
          attrs: {'min-width': 96},
          formatter: (row, column, cellValue, index) => {
            return this.$createElement('el-tag', {
              props: {
                type: this.calculateByValueStatus(cellValue).statusType,
                hit: true
              }
            }, this.calculateByValueStatus(cellValue).statusText)
          }
        },

代码示例见FilterTablePagination

4.Pagination 基于el-pagination 对分页组件进行二次封装

参数名说明类型可选值默认值
currentPage当前页Number-1
pageSize每页条数Number-10
total列表总数Number-0

像其他的一些配置比如pageSizes,layout属性维护在组件的data中,方便统一维护

方法

方法名说明参数
onSizeChange当切换每页显示条数时触发,每次切换会把currentPage置为1。并且会直接改变父组件的pageSize。此处会触发父组件的page-change事件-
onCurrentChange当切换页码时触发;并且会直接改变父组件的currentPage。此处会触发父组件的page-change事件-

注意:由于FilterTablePagination中使用该组件的方式是.sync。所以已经实现了双向绑定

   <Pagination :currentPage.sync='paginationProps.currentPage' :pageSize.sync='paginationProps.pageSize' :total='paginationProps.total'/>

至此,一个页面的三个部分:过滤条件查询,表格展示,分页就已经完成封装了,分别对应FilterForm,BasicTable,Pagination。

这里我们还进行了一个组合式的封装,可以针对大部分普通的表格展示页面,如果有一些复杂的表格,比如表格单元格可编辑,表格行可编辑,这里还没有封装,可以后期根据业务需求扩展。

5.FilterTablePagination

基于FilterForm,BasicTable,Pagination三个组件组合而成的。

参数列表

参数名说明类型可选值默认值
formProps过滤表格组件需要传递的props集合Object--
tableProps表格组件需要传递的props集合Object--
paginationProps分页组件需要传递的props集合Object --

Events (传递给子组件的方法)

方法名说明参数
submit该事件是FilterForm组件会触发的。此处因为是组合组件,实际也是会进行转发,会再触发父组件传过来的loadData方法,进行数据请求-
reset该事件是FilterForm组件会触发的。此处因为是组合组件,实际也是会进行转发,会再触发父组件传过来的loadData方法,进行数据请求-
page-change该事件是Pagination组件会触发的。此处因为是组合组件,实际也是会进行转发,会再触发父组件传过来的loadData方法,进行数据请求-

使用方式

见页面 filterTablePaginationPage 业务中需要关注的地方

  • 1.传入表单,表格,分页需要的相关配置项

  • 2.传入请求列表的参数

  • 3.传入请求列表的方法loadData

  • 4.如果表格有操作项,比如新增,编辑,删除,导出等操作,

所以上面业务中一些通用的数据和方法可以封装在一个mixin中进行逻辑复用。见FilterTablePaginationMixin.js中

6.新增编辑弹窗 模块

此处直接放在业务中,放在对应的modules文件夹中,拆分为表单和弹窗2部分。

  • 1.表单专注于表单自身的业务逻辑,比如表单新增和编辑的项,表单校验,表单提交,代码示例
    async handleSubmit() {
      try {
        const valid = await this.$refs.formRef.validate();
        if (!valid) return Promise.resolve(false);
        let res;
        if (this.formKey === "add") {
          console.log('mock 新增api ,入参是:',this.formData)
          res = await this.mockSaveApi(this.formData);
        } else {
          console.log('mock 编辑api ,入参是:',this.formData)
          res = await this.mockUpdateApi(this.formData);
        }
        if (res.data.code !== 0) {
          this.formKey === "add"
            ? this.$message.error("新增失败," + res.data.msg)
            : this.$message.error("更新失败," + res.data.msg);
          return Promise.resolve(false);
        }
        return Promise.resolve(true);
      } catch (error) {
        console.error("error---", error);
      }
    },

上面示例是因为业务中新增和编辑虽然用的是同一个接口,但请求方式不同,新增是post,修改是put.在api中写了对应的方法。所以做了区分。实际可以根据业务修改。

  • 2.弹窗专注于弹窗自身的逻辑,比如弹窗展示,打开,关闭弹窗。其中注意确认按钮是弹窗中的功能,点击确认需要先校验表单,成功后才能关闭弹窗,重新加载列表数据。代码示例
   // 弹窗确认逻辑 是先提交表单,提交成功后关闭弹窗,加载数据
    async handleConfirm() {
      const isSubmitSuccess = await this.$refs.addEditFormRef.handleSubmit();
      if (!isSubmitSuccess) return;
      this.closeDialog();
      this.$emit("loadData");
    }
全部评论

相关推荐

07-02 10:44
门头沟学院 C++
码农索隆:太实诚了,告诉hr,你能实习至少6个月
点赞 评论 收藏
分享
_mos_:我以为手抄报简历就已经很顶了,没想到还有表格简历
点赞 评论 收藏
分享
找个工作&nbsp;学历是要卡的&nbsp;要求是高的&nbsp;技能不足是真的&nbsp;实习经验是0的&nbsp;简历无处可写是事实的&nbsp;钱不好赚是真的&nbsp;想躺平又不敢躺&nbsp;也不甘心躺&nbsp;怕自己的灵感和才华被掩埋甚至从未被自己发现&nbsp;又质疑自己是否真正有才华
码农索隆:你现在啊,你心里都明白咋回事,但是你没办法改变现状,一想到未来,你又没有信心狠下心来在当下努力。 得走出这种状态,不能一直困在那里面,哪不行就去提升哪,你一动不动那指定改变不了未来,动起来,积少成多才能越来越好
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务