npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

easy-element-components-ui

v1.1.2

Published

一款针对element-ui进行二次封装的简洁高效组件

Readme

Easy Element

基于 vue2x, Element UI 的增强型组件库,提供了更强大的表单、表格、列表等组件,帮助你快速构建后台管理系统。

特性

  • 🚀 基于 Element UI,提供更强大的组件
  • 📦 开箱即用,快速构建后台管理系统
  • 🎨 支持自定义主题,继承 Element UI 的样式系统
  • 🔧 高度可配置,满足各种业务场景
  • 📝 详细的文档和示例
  • 🔥 支持表单联动、动态渲染、自定义校验等高级特性

目录

安装

NPM

npm install easy-element element-ui --save

YARN

yarn add easy-element element-ui

快速开始

完整引入

import Vue from "vue";
import ElementUI from "element-ui";
import EasyElement from "easy-element";
import "element-ui/lib/theme-chalk/index.css";
import "easy-element/lib/theme-chalk/index.css";

Vue.use(ElementUI);
Vue.use(EasyElement);

按需引入

首先,安装 babel-plugin-component:

npm install babel-plugin-component -D

然后,修改 .babelrc:

{
  "plugins": [
    [
      "component",
      {
        "libraryName": "easy-element",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}

接下来,你可以按需引入组件:

import Vue from "vue";
import { EasyElementForm, EasyElementTable } from "easy-element";

Vue.use(EasyElementForm);
Vue.use(EasyElementTable);

组件

Form 表单

表单组件提供了快速创建表单的能力,支持多种输入类型、表单验证、条件渲染等功能。

基础用法

<template>
  <easy-element-form
    v-model="formData"
    :form-item-list="formItemList"
  />
</template>

<script>
export default {
  data() {
    return {
      formData: {},
      formItemList: [
        {
          label: '用户名',
          fromDataKey: 'username',
          cellType: 'input',
          isRequired: true,
          cellAttriBute: {
            props: {
              placeholder: '请输入用户名'
            }
          }
        },
        {
          label: '性别',
          fromDataKey: 'gender',
          cellType: 'select',
          dataSource: {
            labelKey: 'label',
            valueKey: 'value',
            list: [
              { label: '男', value: 1 },
              { label: '女', value: 2 }
            ]
          }
        }
      ]
    }
  }
}
</script>

自定义渲染

使用 format 函数可以完全自定义表单项的渲染内容:

{
  label: '自定义',
  fromDataKey: 'custom',
  format(formData, item, h, value) {
    return h('div', [
      h('el-input', {
        props: {
          value: value
        },
        on: {
          input: (val) => {
            formData[item.fromDataKey] = val
          }
        }
      }),
      h('el-button', {
        on: {
          click: () => {
            // 处理点击事件
          }
        }
      }, '点击')
    ])
  }
}

动态属性配置

cellAttriBute 支持函数形式,可以根据表单数据动态配置组件属性:

{
  label: '动态配置',
  fromDataKey: 'dynamic',
  cellType: 'select',
  cellAttriBute(formData, item) {
    return {
      props: {
        disabled: !formData.isEnabled,
        placeholder: formData.type === 1 ? '请选择' : '暂不可选'
      }
    }
  }
}

API

Props

| 参数 | 说明 | 类型 | 默认值 | | --------------------- | ----------------------------------------------- | ------------------------ | ------ | | v-model / formDataObj | 表单数据对象 | Object | {} | | form-item-list | 表单项配置列表 | Array | [] | | form-attribute | 表单属性配置,继承 el-form 的属性 | Object | {} | | cell-rander-before | 单元格渲染前的处理函数,返回 false 时不渲染该项 | Function(item, formData) | - | | cell-item-format | 表单项格式化函数,可以在渲染前修改配置 | Function(item, formData) | - | | read-only | 是否只读模式 | Boolean | false | | disabled | 是否禁用 | Boolean | false |

FormItem 配置

| 参数 | 说明 | 类型 | 默认值 | | ----------------- | ------------------------------------------------------------------------------------------ | ---------------------------------- | ------ | | label | 表单项标签 | String | - | | fromDataKey | 表单数据的键名 | String | - | | cellType | 单元格类型,可选值:input/select/dateTime/numberInput/floatButton/redioGroup/checkBoxGroup | String | - | | isRequired | 是否必填 | Boolean | false | | cellAttriBute | 单元格组件的属性配置,支持对象或函数形式 | Object/Function(formData, item) | {} | | fromItemAttribute | 表单项属性配置,继承 el-form-item 的属性 | Object | {} | | dataSource | 数据源配置(用于 select/redioGroup/checkBoxGroup) | Object | {} | | format | 自定义渲染函数 | Function(formData, item, h, value) | - |

dataSource 配置

| 参数 | 说明 | 类型 | 默认值 | | -------- | -------------- | ------ | ------ | | labelKey | 选项标签的键名 | String | - | | valueKey | 选项值的键名 | String | - | | list | 选项数据列表 | Array | [] |

Methods

| 方法名 | 说明 | 参数 | | ----------- | ---------------------- | ------------------------------------- | | validate | 表单验证 | - | | getFormData | 获取表单数据,支持验证 | (isValidate = true, isPromise = true) |

表单校验

<template>
  <easy-element-form
    ref="form"
    v-model="formData"
    :form-item-list="formItemList"
  >
    <template #btns>
      <el-button type="primary" @click="handleSubmit">提交</el-button>
      <el-button @click="handleReset">重置</el-button>
    </template>
  </easy-element-form>
</template>

<script>
export default {
  data() {
    return {
      formData: {},
      formItemList: [
        {
          label: '用户名',
          fromDataKey: 'username',
          cellType: 'input',
          fromItemAttribute: {
            props: {
              rules: [
                { required: true, message: '请输入用户名', trigger: 'blur' },
                { min: 3, max: 20, message: '长度在 3 到 20 个字符', trigger: 'blur' }
              ]
            }
          }
        }
      ]
    }
  },
  methods: {
    handleSubmit() {
      this.$refs.form.validate((valid) => {
        if (valid) {
          console.log('表单数据:', this.formData)
        }
      })
    },
    handleReset() {
      this.$refs.form.resetFields()
    }
  }
}
</script>

数据联动

Form 组件提供了多种方式实现表单联动:

  1. 通过 cellAttriBute 函数动态配置组件属性:
{
  label: '城市',
  fromDataKey: 'city',
  cellType: 'select',
  cellAttriBute: (formData) => {
    return {
      props: {
        disabled: !formData.province, // 未选择省份时禁用
        placeholder: formData.province ? '请选择城市' : '请先选择省份'
      }
    }
  }
}
  1. 通过 cellchildVNode 函数动态渲染选项:
{
  label: '城市',
  fromDataKey: 'city',
  cellType: 'select',
  // 动态渲染选项
  cellchildVNode: (formData, item, h) => {
    // 根据省份显示对应的城市列表
    const cityMap = {
      zj: [
        { label: '杭州', value: 'hz' },
        { label: '宁波', value: 'nb' }
      ],
      js: [
        { label: '南京', value: 'nj' },
        { label: '苏州', value: 'sz' }
      ]
    }
    const cityList = cityMap[formData.province] || []
    return cityList.map(city => {
      return h('el-option', {
        props: {
          key: city.value,
          label: city.label,
          value: city.value
        }
      })
    })
  }
}
  1. 通过 cellRanderBefore 函数控制表单项的显示/隐藏:
{
  label: '其他信息',
  fromDataKey: 'otherInfo',
  cellType: 'input',
  cellRanderBefore: (item, formData) => {
    // 当类型为 "other" 时显示
    return formData.type === 'other'
  }
}
  1. 通过 format 函数实现复杂的自定义联动:
{
  label: '自定义联动',
  fromDataKey: 'custom',
  format: (formData, item, h, value) => {
    // 根据条件返回不同的渲染内容
    if (formData.type === 'text') {
      return h('el-input', {
        props: {
          value: value
        },
        on: {
          input: (val) => {
            formData[item.fromDataKey] = val
          }
        }
      })
    } else if (formData.type === 'select') {
      return h('el-select', {
        props: {
          value: value
        },
        on: {
          input: (val) => {
            formData[item.fromDataKey] = val
          }
        }
      }, [
        h('el-option', {
          props: {
            label: '选项1',
            value: 1
          }
        }),
        h('el-option', {
          props: {
            label: '选项2',
            value: 2
          }
        })
      ])
    }
  }
}

完整的联动示例:

<template>
  <easy-element-form
    ref="form"
    v-model="formData"
    :form-item-list="formItemList"
    :cell-rander-before="cellRanderBefore"
  />
</template>

<script>
export default {
  data() {
    return {
      formData: {},
      formItemList: [
        {
          label: '省份',
          fromDataKey: 'province',
          cellType: 'select',
          dataSource: {
            labelKey: 'label',
            valueKey: 'value',
            list: [
              { label: '浙江', value: 'zj' },
              { label: '江苏', value: 'js' }
            ]
          }
        },
        {
          label: '城市',
          fromDataKey: 'city',
          cellType: 'select',
          // 动态禁用/启用
          cellAttriBute: (formData) => ({
            props: {
              disabled: !formData.province,
              placeholder: formData.province ? '请选择城市' : '请先选择省份'
            }
          }),
          // 基础数据源配置
          dataSource: {
            labelKey: 'label',
            valueKey: 'value',
            list: []
          },
          // 动态渲染选项
          cellchildVNode: (formData, item, h) => {
            const cityMap = {
              zj: [
                { label: '杭州', value: 'hz' },
                { label: '宁波', value: 'nb' }
              ],
              js: [
                { label: '南京', value: 'nj' },
                { label: '苏州', value: 'sz' }
              ]
            }
            const cityList = cityMap[formData.province] || []
            return cityList.map(city => {
              return h('el-option', {
                props: {
                  key: city.value,
                  label: city.label,
                  value: city.value
                }
              })
            })
          }
        },
        {
          label: '类型',
          fromDataKey: 'type',
          cellType: 'select',
          dataSource: {
            labelKey: 'label',
            valueKey: 'value',
            list: [
              { label: '个人', value: 1 },
              { label: '企业', value: 2 }
            ]
          }
        },
        {
          label: '身份证号',
          fromDataKey: 'idCard',
          cellType: 'input'
        },
        {
          label: '营业执照',
          fromDataKey: 'license',
          cellType: 'input'
        }
      ]
    }
  },
  methods: {
    cellRanderBefore(item, formData) {
      // 根据类型控制表单项的显示/隐藏
      if (item.fromDataKey === 'idCard') {
        return formData.type === 1
      }
      if (item.fromDataKey === 'license') {
        return formData.type === 2
      }
      return true
    }
  },
  watch: {
    // 当省份变化时,清空城市选择
    'formData.province'(val) {
      this.formData.city = ''
    }
  }
}
</script>

这个示例展示了:

  1. 省市联动:

    • 城市选择器根据省份动态启用/禁用
    • 城市选项通过 cellchildVNode 动态渲染
    • 切换省份时自动清空城市选择
  2. 条件显示:

    • 根据类型显示不同的证件输入框(个人显示身份证号,企业显示营业执照)
    • 通过 cell-rander-before 控制显示/隐藏
  3. 动态渲染:

    • 根据类型切换不同的表单控件

QueryForm 查询表单

基于 Form 组件封装的查询表单组件,提供了快速配置查询条件、按钮和布局的能力。

基础用法

<template>
  <easy-element-query-form
    ref="queryForm"
    v-model="formData"
    :form-item-list="formItemList"
    :get-query-data-call-back="handleQuery"
  />
</template>

<script>
export default {
  data() {
    return {
      formData: {},
      formItemList: [
        {
          label: '用户名',
          fromDataKey: 'username',
          cellType: 'input',
          cellAttriBute: {
            attrs: {
              placeholder: '请输入用户名',
              clearable: true
            }
          }
        },
        {
          label: '状态',
          fromDataKey: 'status',
          cellType: 'select',
          dataSource: {
            labelKey: 'label',
            valueKey: 'value',
            list: [
              { label: '全部', value: '' },
              { label: '启用', value: 1 },
              { label: '禁用', value: 0 }
            ]
          }
        }
      ]
    }
  },
  methods: {
    handleQuery(queryData) {
      console.log('查询参数:', queryData)
    }
  }
}
</script>

自定义按钮

<template>
  <easy-element-query-form
    ref="queryForm"
    v-model="formData"
    :form-item-list="formItemList"
    :get-query-data-call-back="handleQuery"
    :is-show-default-btn="false"
  >
    <template #btns>
      <el-button type="primary" @click="handleSearch">查询</el-button>
      <el-button @click="handleReset">重置</el-button>
      <el-button type="success" @click="handleExport">导出</el-button>
    </template>
  </easy-element-query-form>
</template>

<script>
export default {
  data() {
    return {
      formData: {},
      formItemList: [
        {
          label: '用户名',
          fromDataKey: 'username',
          cellType: 'input'
        }
      ]
    }
  },
  methods: {
    handleSearch() {
      const queryData = this.$refs.queryForm.getQueryData()
      console.log('查询:', queryData)
    },
    handleReset() {
      this.$refs.queryForm.resetFields()
    },
    handleExport() {
      const queryData = this.$refs.queryForm.getQueryData()
      console.log('导出:', queryData)
    }
  }
}
</script>

API

Props

| 参数 | 说明 | 类型 | 默认值 | | ------------------------ | --------------------------------- | ------------------- | ------ | | form-item-list | 表单项配置列表 | Array | [] | | get-query-data-call-back | 查询回调函数 | Function(queryData) | - | | is-show-default-btn | 是否显示默认按钮(查询、重置) | Boolean | true | | query-btn-config | 查询按钮配置 | Object | {} | | reset-btn-config | 重置按钮配置 | Object | {} | | form-attribute | 表单属性配置,继承 el-form 的属性 | Object | {} |

Methods

| 方法名 | 说明 | 参数 | | ------------ | ------------ | ---- | | getQueryData | 获取查询参数 | - | | resetFields | 重置表单 | - | | validate | 表单校验 | - |

Events

| 事件名 | 说明 | 参数 | | ------ | ------------------ | ------------------- | | query | 点击查询按钮时触发 | (queryData: Object) | | reset | 点击重置按钮时触发 | - |

Slots

| 插槽名 | 说明 | | ------ | -------------- | | btns | 自定义按钮区域 |

DataList 数据列表

基于 QueryForm 和 Table 组件的组合组件,提供了完整的数据列表解决方案,包括查询条件、数据展示和分页功能。

基础用法

<template>
  <easy-element-data-list
    ref="dataList"
    :query-form-attribute="queryFormAttribute"
    :table-attribute="tableAttribute"
    :get-data-callback="getDataCallback"
    :is-enable-query-model="true"
    :is-enable-pagination="true"
  />
</template>

<script>
export default {
  data() {
    return {
      // 查询表单配置
      queryFormAttribute: {
        formItemList: [
          {
            label: '用户名',
            fromDataKey: 'username',
            cellType: 'input'
          },
          {
            label: '状态',
            fromDataKey: 'status',
            cellType: 'select',
            dataSource: {
              labelKey: 'label',
              valueKey: 'value',
              list: [
                { label: '启用', value: 1 },
                { label: '禁用', value: 0 }
              ]
            }
          }
        ]
      },
      // 表格配置
      tableAttribute: {
        columns: [
          {
            props: {
              prop: 'username',
              label: '用户名'
            }
          },
          {
            props: {
              prop: 'status',
              label: '状态'
            },
            defaultComponents: {
              cellType: 'select',
              dataSource: {
                labelKey: 'label',
                valueKey: 'value',
                list: [
                  { label: '启用', value: 1 },
                  { label: '禁用', value: 0 }
                ]
              }
            }
          },
          {
            props: {
              prop: 'operation',
              label: '操作',
              width: '150px',
              fixed: 'right'
            },
            format: (h, scope) => {
              return [
                h('el-button', {
                  props: {
                    type: 'text',
                    size: 'small'
                  },
                  on: {
                    click: () => this.handleEdit(scope.row)
                  }
                }, '编辑'),
                h('el-button', {
                  props: {
                    type: 'text',
                    size: 'small',
                    type: 'danger'
                  },
                  on: {
                    click: () => this.handleDelete(scope.row)
                  }
                }, '删除')
              ]
            }
          }
        ]
      }
    }
  },
  methods: {
    // 获取数据的回调函数
    async getDataCallback(params) {
      try {
        const res = await this.fetchData(params)
        return {
          data: res.data,
          total: res.total
        }
      } catch (error) {
        return {
          data: [],
          total: 0
        }
      }
    },
    // 编辑
    handleEdit(row) {
      console.log('编辑:', row)
    },
    // 删除
    handleDelete(row) {
      console.log('删除:', row)
    },
    // 刷新列表
    refreshList() {
      this.$refs.dataList.refresh()
    }
  }
}
</script>

API

Props

| 参数 | 说明 | 类型 | 默认值 | | --------------------- | ------------------------------ | ---------------- | ------ | | query-form-attribute | 查询表单配置 | Object | {} | | table-attribute | 表格配置 | Object | {} | | get-data-callback | 获取数据的回调函数 | Function(params) | - | | is-enable-query-model | 是否启用查询模式 | Boolean | true | | is-enable-pagination | 是否启用分页 | Boolean | true | | pagination-attribute | 分页配置 | Object | {} | | is-show-default-btn | 是否显示默认按钮(查询、重置) | Boolean | true | | query-btn-config | 查询按钮配置 | Object | {} | | reset-btn-config | 重置按钮配置 | Object | {} |

Methods

| 方法名 | 说明 | 参数 | | ------------ | ------------ | ---- | | refresh | 刷新列表数据 | - | | resetFields | 重置查询表单 | - | | getQueryData | 获取查询参数 | - |

Events

| 事件名 | 说明 | 参数 | | -------------- | ------------------ | ------------------- | | query | 点击查询按钮时触发 | (queryData: Object) | | reset | 点击重置按钮时触发 | - | | size-change | 分页大小改变时触发 | (size: Number) | | current-change | 当前页改变时触发 | (current: Number) |

Table 表格组件

基于 Element UI 的 Table 组件封装,支持快速配置列、自定义渲染、排序、编辑等功能。

基础用法

<template>
  <easy-element-table
    :data="tableData"
    :columns="columns"
  />
</template>

<script>
export default {
  data() {
    return {
      tableData: [
        {
          id: 1,
          name: '张三',
          age: 25,
          status: 1
        }
      ],
      columns: [
        {
          props: {
            prop: 'name',
            label: '姓名'
          }
        },
        {
          props: {
            prop: 'age',
            label: '年龄'
          },
          defaultComponents: {
            cellType: 'numberInput'
          }
        },
        {
          props: {
            prop: 'status',
            label: '状态'
          },
          defaultComponents: {
            cellType: 'select',
            dataSource: {
              labelKey: 'label',
              valueKey: 'value',
              list: [
                { label: '启用', value: 1 },
                { label: '禁用', value: 0 }
              ]
            }
          }
        }
      ]
    }
  }
}
</script>

可编辑表格

<template>
  <easy-element-table
    :data="tableData"
    :columns="columns"
    :is-enable-edit="true"
    @cell-value-change="handleCellChange"
  />
</template>

<script>
export default {
  data() {
    return {
      tableData: [
        {
          id: 1,
          name: '张三',
          age: 25,
          status: 1
        }
      ],
      columns: [
        {
          props: {
            prop: 'name',
            label: '姓名'
          },
          defaultComponents: {
            cellType: 'input'
          }
        },
        {
          props: {
            prop: 'age',
            label: '年龄'
          },
          defaultComponents: {
            cellType: 'numberInput'
          }
        },
        {
          props: {
            prop: 'status',
            label: '状态'
          },
          defaultComponents: {
            cellType: 'select',
            dataSource: {
              labelKey: 'label',
              valueKey: 'value',
              list: [
                { label: '启用', value: 1 },
                { label: '禁用', value: 0 }
              ]
            }
          }
        }
      ]
    }
  },
  methods: {
    handleCellChange({ row, prop, value }) {
      console.log('单元格值变更:', row, prop, value)
    }
  }
}
</script>

API

Props

| 参数 | 说明 | 类型 | 默认值 | | ------------------- | ---------------------------------- | ------- | ------ | | data | 表格数据 | Array | [] | | columns | 列配置 | Array | [] | | is-enable-edit | 是否启用编辑模式 | Boolean | false | | is-enable-selection | 是否启用多选 | Boolean | false | | table-attribute | 表格属性配置,继承 el-table 的属性 | Object | {} |

Column 配置

| 参数 | 说明 | 类型 | 默认值 | | ----------------- | --------------------------------------- | ------------------ | ------ | | props | 列属性配置,继承 el-table-column 的属性 | Object | {} | | format | 自定义渲染函数 | Function(h, scope) | - | | defaultComponents | 默认组件配置,用于编辑模式 | Object | {} |

Methods

| 方法名 | 说明 | 参数 | | ------------------ | -------------------- | --------------- | | getSelectedRows | 获取选中行数据 | - | | clearSelection | 清空选中状态 | - | | toggleRowSelection | 切换某一行的选中状态 | (row, selected) |

Events

| 事件名 | 说明 | 参数 | | ----------------- | -------------------- | -------------------- | | cell-value-change | 单元格值变更时触发 | { row, prop, value } | | selection-change | 选中项发生变化时触发 | selection | | row-click | 行点击时触发 | row, column, event |

通用配置

cellType 类型

组件库提供了以下几种单元格类型,每种类型都有其特定的必填参数和可选参数:

| 类型 | 说明 | 必填参数 | 可选参数 | 备注 | | ------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | | input | 输入框 | - | type: 输入框类型maxlength: 最大长度showWordLimit: 是否显示字数统计 | type 支持 text、textarea、password 等默认启用 clearable | | select | 下拉选择器 | dataSource: {  labelKey: 显示字段名  valueKey: 值字段名  list: 选项数组} | filterable: 是否可搜索multiple: 是否多选remote: 是否远程搜索remoteMethod: 远程搜索方法 | 支持本地数据和远程搜索默认启用 clearable | | dateTime | 日期时间选择器 | - | type: 选择器类型valueFormat: 值格式dataTimeSetting: {  maxDate: 最大日期  minDate: 最小日期  dateInterval: 日期间隔} | type 支持:date/datetime/daterange/datetimerange/monthrange默认值格式:yyyy-MM-dd | | numberInput | 数字输入框 | - | min: 最小值max: 最大值precision: 精度step: 步长 | 支持精度控制和步进设置默认启用 clearable | | floatButton | 浮点数输入框 | - | min: 最小值max: 最大值precision: 精度append: 后缀(如 %) | 支持百分比等特殊格式当 append="%" 时自动处理百分比转换 | | radioGroup | 单选框组 | dataSource: {  labelKey: 显示字段名  valueKey: 值字段名  list: 选项数组} | - | - | | checkBoxGroup | 复选框组 | dataSource: {  labelKey: 显示字段名  valueKey: 值字段名  list: 选项数组} | min: 最小选中数max: 最大选中数 | - |

示例:

  1. select 类型(必填 dataSource):
{
  cellType: 'select',
  dataSource: {
    labelKey: 'label',
    valueKey: 'value',
    list: [
      { label: '选项1', value: 1 },
      { label: '选项2', value: 2 }
    ]
  }
}
  1. dateTime 类型(带日期限制):
{
  cellType: 'dateTime',
  cellAttriBute: {
    props: {
      type: 'daterange'
    }
  },
  dataTimeSetting: {
    maxDate: new Date('2024-12-31'),
    minDate: new Date('2024-01-01'),
    dateInterval: 30 // 日期范围最大间隔30天
  }
}
  1. numberInput 类型(带精度和范围限制):
{
  cellType: 'numberInput',
  cellAttriBute: {
    props: {
      min: 0,
      max: 100,
      precision: 2,
      step: 0.1
    }
  }
}
  1. floatButton 类型(百分比格式):
{
  cellType: 'floatButton',
  cellAttriBute: {
    props: {
      precision: 2,
      min: 0,
      max: 1
    },
    attrs: {
      append: '%'
    }
  }
}

数据源配置

用于 select、radioGroup、checkBoxGroup 等需要选项数据的组件:

{
  // 显示字段名
  labelKey: 'label',
  // 值字段名
  valueKey: 'value',
  // 数据列表
  list: [
    { label: '选项1', value: 1 },
    { label: '选项2', value: 2 }
  ]
}

表单校验

表单校验规则继承自 Element UI 的表单校验规则,在 fromItemAttribute.props.rules 中配置:

{
  fromItemAttribute: {
    props: {
      rules: [
        { required: true, message: "必填项" },
        { min: 3, max: 20, message: "长度在 3 到 20 个字符" },
        { type: "email", message: "请输入正确的邮箱地址" },
        {
          validator: (rule, value, callback) => {
            if (value === "") {
              callback(new Error("请输入"));
            } else if (value < 0) {
              callback(new Error("不能小于0"));
            } else {
              callback();
            }
          },
          trigger: "blur",
        },
      ];
    }
  }
}

自定义渲染

通过 format 函数可以实现完全自定义的渲染内容,函数接收以下参数:

  • formData/row: 当前行/表单数据
  • item/column: 当前配置项
  • h: 渲染函数
  • value: 当前字段值(可选)
{
  format: (formData, item, h, value) => {
    return h("div", [
      h("el-input", {
        props: {
          value: value,
        },
        on: {
          input: (val) => {
            formData[item.fromDataKey] = val;
          },
        },
      }),
      h(
        "el-button",
        {
          props: {
            type: "text",
          },
          on: {
            click: () => {
              // 处理点击事件
            },
          },
        },
        "按钮"
      ),
    ]);
  };
}

条件渲染

通过 cell-rander-before 属性可以控制表单项的显示/隐藏:

<template>
  <easy-element-form
    ref="form"
    v-model="formData"
    :form-item-list="formItemList"
    :cell-rander-before="cellRanderBefore"
  />
</template>

<script>
export default {
  data() {
    return {
      formData: {},
      formItemList: [
        {
          label: '类型',
          fromDataKey: 'type',
          cellType: 'select',
          dataSource: {
            labelKey: 'label',
            valueKey: 'value',
            list: [
              { label: '个人', value: 1 },
              { label: '企业', value: 2 }
            ]
          }
        },
        {
          label: '身份证号',
          fromDataKey: 'idCard',
          cellType: 'input'
        },
        {
          label: '营业执照',
          fromDataKey: 'license',
          cellType: 'input'
        }
      ]
    }
  },
  methods: {
    cellRanderBefore(item, formData) {
      // 根据类型控制表单项的显示/隐藏
      if (item.fromDataKey === 'idCard') {
        return formData.type === 1
      }
      if (item.fromDataKey === 'license') {
        return formData.type === 2
      }
      return true
    }
  }
}
</script>

在上面的示例中:

  • 当类型选择"个人"时,显示身份证号输入框
  • 当类型选择"企业"时,显示营业执照输入框
  • 类型选择框始终显示

动态属性

cellAttriButefromItemAttribute 支持函数形式,可以根据数据动态返回配置:

{
  cellAttriBute: (formData) => ({
    props: {
      disabled: formData.status === 0,
    },
  });
}

常见问题

如何实现表单联动?

可以通过以下几种方式实现表单联动:

  1. 监听 formData 的变化:
watch: {
  'formData.type'(newType) {
    // 根据类型变化清空或设置其他字段
    this.formData.content = ''
  }
}
  1. 使用 cell-rander-before 控制显示隐藏:
<easy-element-form
  v-model="formData"
  :form-item-list="formItemList"
  :cell-rander-before="cellRanderBefore"
/>

methods: {
  cellRanderBefore(item, formData) {
    // 根据类型控制表单项的显示/隐藏
    if (item.fromDataKey === 'idCard') {
      return formData.type === 1
    }
    if (item.fromDataKey === 'license') {
      return formData.type === 2
    }
    return true
  }
}
  1. 使用动态属性配置:
{
  cellAttriBute: (formData) => ({
    props: {
      disabled: formData.status === 0,
    },
  });
}
  1. 使用 cellchildVNode 动态渲染选项:
{
  label: '城市',
  fromDataKey: 'city',
  cellType: 'select',
  // 基础数据源配置
  dataSource: {
    labelKey: 'label',
    valueKey: 'value',
    list: []
  },
  // 动态渲染选项
  cellchildVNode: (formData, item, h) => {
    const cityMap = {
      zj: [
        { label: '杭州', value: 'hz' },
        { label: '宁波', value: 'nb' }
      ],
      js: [
        { label: '南京', value: 'nj' },
        { label: '苏州', value: 'sz' }
      ]
    }
    const cityList = cityMap[formData.province] || []
    return cityList.map(city => {
      return h('el-option', {
        props: {
          key: city.value,
          label: city.label,
          value: city.value
        }
      })
    })
  }
}

完整的联动示例:

<template>
  <easy-element-form
    ref="form"
    v-model="formData"
    :form-item-list="formItemList"
    :cell-rander-before="cellRanderBefore"
  />
</template>

<script>
export default {
  data() {
    return {
      formData: {},
      formItemList: [
        {
          label: '省份',
          fromDataKey: 'province',
          cellType: 'select',
          dataSource: {
            labelKey: 'label',
            valueKey: 'value',
            list: [
              { label: '浙江', value: 'zj' },
              { label: '江苏', value: 'js' }
            ]
          }
        },
        {
          label: '城市',
          fromDataKey: 'city',
          cellType: 'select',
          // 动态禁用/启用
          cellAttriBute: (formData) => ({
            props: {
              disabled: !formData.province,
              placeholder: formData.province ? '请选择城市' : '请先选择省份'
            }
          }),
          // 基础数据源配置
          dataSource: {
            labelKey: 'label',
            valueKey: 'value',
            list: []
          },
          // 动态渲染选项
          cellchildVNode: (formData, item, h) => {
            const cityMap = {
              zj: [
                { label: '杭州', value: 'hz' },
                { label: '宁波', value: 'nb' }
              ],
              js: [
                { label: '南京', value: 'nj' },
                { label: '苏州', value: 'sz' }
              ]
            }
            const cityList = cityMap[formData.province] || []
            return cityList.map(city => {
              return h('el-option', {
                props: {
                  key: city.value,
                  label: city.label,
                  value: city.value
                }
              })
            })
          }
        },
        {
          label: '类型',
          fromDataKey: 'type',
          cellType: 'select',
          dataSource: {
            labelKey: 'label',
            valueKey: 'value',
            list: [
              { label: '个人', value: 1 },
              { label: '企业', value: 2 }
            ]
          }
        },
        {
          label: '身份证号',
          fromDataKey: 'idCard',
          cellType: 'input'
        },
        {
          label: '营业执照',
          fromDataKey: 'license',
          cellType: 'input'
        }
      ]
    }
  },
  methods: {
    cellRanderBefore(item, formData) {
      // 根据类型控制表单项的显示/隐藏
      if (item.fromDataKey === 'idCard') {
        return formData.type === 1
      }
      if (item.fromDataKey === 'license') {
        return formData.type === 2
      }
      return true
    }
  },
  watch: {
    // 当省份变化时,清空城市选择
    'formData.province'(val) {
      this.formData.city = ''
    }
  }
}
</script>

这个示例展示了:

  1. 省市联动:

    • 城市选择器根据省份动态启用/禁用
    • 城市选项通过 cellchildVNode 动态渲染
    • 切换省份时自动清空城市选择
  2. 条件显示:

    • 根据类型显示不同的证件输入框(个人显示身份证号,企业显示营业执照)
    • 通过 cell-rander-before 控制显示/隐藏
  3. 动态渲染:

    • 根据类型切换不同的表单控件

如何实现远程搜索?

在 select 类型的组件中配置 remote 相关属性:

{
  cellType: 'select',
  cellAttriBute: {
    props: {
      filterable: true,
      remote: true,
      remoteMethod: (query) => {
        // 远程搜索逻辑
        return searchAPI(query).then(res => {
          this.options = res.data
        })
      }
    }
  }
}

如何自定义校验规则?

可以在 rules 中使用 validator 函数实现自定义校验:

{
  fromItemAttribute: {
    props: {
      rules: [
        {
          validator: (rule, value, callback) => {
            if (value === "") {
              callback(new Error("请输入"));
            } else if (!/^[A-Z]/.test(value)) {
              callback(new Error("必须以大写字母开头"));
            } else {
              callback();
            }
          },
          trigger: "blur",
        },
      ];
    }
  }
}

完整的增删改查示例

下面是一个完整的用户管理示例,包含查询、新增、编辑、删除功能:

<template>
  <div class="user-management">
    <!-- 数据列表组件 -->
    <easy-element-data-list
      ref="dataList"
      :query-form-attribute="queryFormAttribute"
      :table-attribute="tableAttribute"
      :get-data-callback="getDataCallback"
      :is-enable-query-model="true"
      :is-enable-pagination="true"
    />

    <!-- 新增/编辑弹窗 -->
    <el-dialog
      :title="dialogTitle"
      :visible.sync="dialogVisible"
      width="500px"
      @close="handleDialogClose"
    >
      <easy-element-form
        ref="form"
        v-model="formData"
        :form-item-list="formItemList"
      />
      <div slot="footer">
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="handleSubmit">确定</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
export default {
  data() {
    return {
      // 查询表单配置
      queryFormAttribute: {
        formItemList: [
          {
            label: '用户名',
            fromDataKey: 'username',
            cellType: 'input',
            cellAttriBute: {
              attrs: {
                placeholder: '请输入用户名',
                clearable: true
              }
            }
          },
          {
            label: '部门',
            fromDataKey: 'department',
            cellType: 'select',
            dataSource: {
              labelKey: 'label',
              valueKey: 'value',
              list: [
                { label: '技术部', value: 'tech' },
                { label: '产品部', value: 'product' },
                { label: '运营部', value: 'operation' }
              ]
            }
          },
          {
            label: '入职日期',
            fromDataKey: 'joinDate',
            cellType: 'dateTime',
            cellAttriBute: {
              props: {
                type: 'daterange',
                startPlaceholder: '开始日期',
                endPlaceholder: '结束日期'
              }
            }
          }
        ]
      },
      // 表格配置
      tableAttribute: {
        columns: [
          {
            props: {
              prop: 'username',
              label: '用户名'
            }
          },
          {
            props: {
              prop: 'department',
              label: '部门'
            },
            format: (h, { row }) => {
              const deptMap = {
                tech: '技术部',
                product: '产品部',
                operation: '运营部'
              }
              return h('span', deptMap[row.department] || '-')
            }
          },
          {
            props: {
              prop: 'email',
              label: '邮箱'
            }
          },
          {
            props: {
              prop: 'joinDate',
              label: '入职日期'
            }
          },
          {
            props: {
              prop: 'status',
              label: '状态'
            },
            format: (h, { row }) => {
              return h('el-tag', {
                props: {
                  type: row.status === 1 ? 'success' : 'info'
                }
              }, row.status === 1 ? '在职' : '离职')
            }
          },
          {
            props: {
              prop: 'operation',
              label: '操作',
              width: '180px',
              fixed: 'right'
            },
            format: (h, { row }) => {
              return [
                h('el-button', {
                  props: {
                    type: 'text',
                    size: 'small'
                  },
                  on: {
                    click: () => this.handleEdit(row)
                  }
                }, '编辑'),
                h('el-button', {
                  props: {
                    type: 'text',
                    size: 'small',
                    type: 'danger'
                  },
                  on: {
                    click: () => this.handleDelete(row)
                  }
                }, '删除')
              ]
            }
          }
        ]
      },
      // 弹窗表单配置
      formItemList: [
        {
          label: '用户名',
          fromDataKey: 'username',
          cellType: 'input',
          isRequired: true,
          fromItemAttribute: {
            props: {
              rules: [
                { required: true, message: '请输入用户名', trigger: 'blur' },
                { min: 2, max: 20, message: '长度在 2 到 20 个字符', trigger: 'blur' }
              ]
            }
          }
        },
        {
          label: '部门',
          fromDataKey: 'department',
          cellType: 'select',
          isRequired: true,
          dataSource: {
            labelKey: 'label',
            valueKey: 'value',
            list: [
              { label: '技术部', value: 'tech' },
              { label: '产品部', value: 'product' },
              { label: '运营部', value: 'operation' }
            ]
          }
        },
        {
          label: '邮箱',
          fromDataKey: 'email',
          cellType: 'input',
          isRequired: true,
          fromItemAttribute: {
            props: {
              rules: [
                { required: true, message: '请输入邮箱', trigger: 'blur' },
                { type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' }
              ]
            }
          }
        },
        {
          label: '入职日期',
          fromDataKey: 'joinDate',
          cellType: 'dateTime',
          isRequired: true
        },
        {
          label: '状态',
          fromDataKey: 'status',
          cellType: 'radioGroup',
          dataSource: {
            labelKey: 'label',
            valueKey: 'value',
            list: [
              { label: '在职', value: 1 },
              { label: '离职', value: 0 }
            ]
          }
        }
      ],
      // 弹窗数据
      dialogVisible: false,
      dialogTitle: '新增用户',
      formData: {},
      editingId: null
    }
  },
  methods: {
    // 获取列表数据
    async getDataCallback(params) {
      try {
        // 这里调用实际的接口
        const res = await this.fetchUserList({
          ...params,
          ...params.queryData // 合并查询条件
        })
        return {
          data: res.data,
          total: res.total
        }
      } catch (error) {
        this.$message.error('获取数据失败')
        return {
          data: [],
          total: 0
        }
      }
    },

    // 打开新增弹窗
    handleAdd() {
      this.dialogTitle = '新增用户'
      this.dialogVisible = true
      this.editingId = null
      this.formData = {
        status: 1 // 默认在职
      }
    },

    // 打开编辑弹窗
    handleEdit(row) {
      this.dialogTitle = '编辑用户'
      this.dialogVisible = true
      this.editingId = row.id
      // 复制一份数据,避免直接修改表格数据
      this.formData = { ...row }
    },

    // 删除
    handleDelete(row) {
      this.$confirm('确认删除该用户?', '提示', {
        type: 'warning'
      }).then(async () => {
        try {
          // 调用删除接口
          await this.deleteUser(row.id)
          this.$message.success('删除成功')
          // 刷新列表
          this.$refs.dataList.refresh()
        } catch (error) {
          this.$message.error('删除失败')
        }
      }).catch(() => {})
    },

    // 提交表单
    handleSubmit() {
      this.$refs.form.validate(async (valid) => {
        if (valid) {
          try {
            if (this.editingId) {
              // 编辑
              await this.updateUser({
                id: this.editingId,
                ...this.formData
              })
              this.$message.success('更新成功')
            } else {
              // 新增
              await this.createUser(this.formData)
              this.$message.success('创建成功')
            }
            // 关闭弹窗
            this.dialogVisible = false
            // 刷新列表
            this.$refs.dataList.refresh()
          } catch (error) {
            this.$message.error(this.editingId ? '更新失败' : '创建失败')
          }
        }
      })
    },

    // 关闭弹窗
    handleDialogClose() {
      this.$refs.form.resetFields()
      this.formData = {}
      this.editingId = null
    },

    // API 调用方法
    async fetchUserList(params) {
      // 实现查询接口调用
      return await this.$http.get('/api/users', { params })
    },

    async createUser(data) {
      // 实现创建接口调用
      return await this.$http.post('/api/users', data)
    },

    async updateUser(data) {
      // 实现更新接口调用
      return await this.$http.put(`/api/users/${data.id}`, data)
    },

    async deleteUser(id) {
      // 实现删除接口调用
      return await this.$http.delete(`/api/users/${id}`)
    }
  }
}
</script>

<style>
.user-management {
  padding: 20px;
}
</style>

这个示例展示了:

  1. 查询条件配置:

    • 支持输入框(用户名)
    • 下拉选择(部门)
    • 日期范围选择(入职日期)
  2. 表格展示:

    • 自定义列渲染(部门名称映射、状态标签)
    • 操作列(编辑、删除按钮)
  3. 新增/编辑表单:

    • 表单验证
    • 多种输入类型
    • 默认值设置
    • 表单重置
  4. 完整的数据处理流程:

    • 列表数据获取
    • 新增/编辑/删除操作
    • 刷新列表
    • 错误处理
  5. 组件间联动:

    • DataList 和 Form 组件配合使用
    • 弹窗组件集成
    • 确认框交互