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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@mecc/form

v1.2.0

Published

Advanced vue form component based on el-form.

Downloads

6

Readme

@mecc/form

Intro 简介

@mecc/form 是一款表单组件,基于 vueelement-ui 进行的二次封装,无需繁琐的模板代码,所有的表单配置项均可通过属性传递,使你的代码更干净。

Feature 特色

  • @mecc/form 没有预设表单组件,所有表单组件均通过 render 属性传递,通过灵活的 JSX 语法实现高度自定义组件,因此,它非常小巧,不过需要提前安装 vueelement-ui

  • @mecc/form 底层采用 $attrs$listeners 接收参数和监听事件,无缝对接 element-ui 中的 Form 文档板块,上手更快(所有 <el-form> 接受的参数 <mecc-form> 都支持,所有 <el-form-item> 接受的参数,column都有相应的字段可以设置,所有的方法、事件和插槽,除了 Form-Item Methods,其他都支持);

  • 针对简单场景,可传递 formatter 属性进行格式化输出,在绑定了表单的情况下,可省略 renderformatter 属性,@mecc/form 会默认返回 <span> 标签包裹的表单值,当然,你还可以自定义当前的 class

  • 针对复杂表单,比如你的表单可能是下面这样,@mecc/form 可以满足你!

export default {
  data() {
    return {
      form: {
        name: '',
        time: {
          start: '2020/01',
          end: '2020/03'
        },
        hobby: [
          sport: { name: 'basketball', point: 10 },
          drink: { name: 'tea', point: 9 } // 根据需要可以动态增减
        ]
}
  • 表单需要远程搜索?没问题!

  • 更复杂的场景,想使用自定义组件?没问题!

  • 表单太庞大,考虑模块化开发,方便复用?没问题!

Install 安装

  • 通过 npm 或者 yarn 安装项目
npm i @mecc/form
# 或者
yarn add @mecc/form
  • 引用组件,根据需要可全局引入或者局部引入
// 组件依赖 vue 和 element-ui

// 全局引入,可配置选项
// >>> main.js
import Vue from 'vue'
import Element from 'element-ui'
import 'element-ui/libs/theme-chalk/index.css'

import MeccForm from '@mecc/form'
Vue.use(MeccForm, {
  emptyText: '--'  // 没有内容的占位符,默认为空
})

// 局部引入
// >>> Demo.vue
<script>
import MeccForm from '@mecc/form'
export default {
    components: {
        MeccForm
    }
}
</script>

Options 配置项

配置项内容可在全局引入时设置,或者直接使用 <mecc-form {...options} /> ,需注意:直接使用的优先级高于全局配置

| 参数 | 数据类型 | 默认值 | 可选值 | 说明 | |:---------:|:--------:|:------:|:------:|:----------------------------:| | emptyText | String | '-' | - | 表单数据为空时显示的文本内容 | | formClass | String | '' | - | 自定义class名称 |

Form Attributes 表单属性

仅展示必填项和新增项,其余参数见 Element Doc Form #Form Attributes

| 参数 | 数据类型 | 是否必须 | 默认值 | 可选值 | 说明 | |:------:|:--------:|:--------:|:------:|:------:|:--------------------------------:| | column | Array | 是 | - | - | 表单列配置项,具体内容见下方说明 | | model | Object | 是 | - | - | 表单数据 |

Form Methods 表单方法

支持全部 el-form 方法,详见 Element Doc Form #Form Methods

Form Events 表单事件

支持全部 el-form 方法,详见 Element Doc Form #Form Events

Form-Item Attributes 表单列属性

支持全部 el-form-item 属性,详见 Element Doc Form #Form Events

Form-Item Methods 表单列方法

暂不支持

Column 列配置项

仅展示必填项和新增项,其余参数见 Element Doc Form #Form-column Attributes

| 参数 | 数据类型 | 是否必须 | 说明 | |:-----------:|:-------------------------------------:|:--------:|:---------------------------------------------------------------------------------:| | prop | String | 是 | 设置表单列的别名 | | label | String | 是 | 设置表单列的显示标签 | | render | Function(h, form, root) => VNode | 否 | 自定义渲染内容,可选返回VNode | | formatter | Function(form, root) => string | 否 | 自定义渲染内容,可选返回字符串 | | children | Array | 否 | 当数据项类型为[object]时使用,返回column数组,与render/item互斥 | | item | Function(form, root) => [column, ...] | 否 | 当数据项类型为[array]时使用,可动态增删子节点,返回column数组,与render/children互斥 | | value | - | 否 | 当上一级数据项类型为[array],切传递了[item]属性时使用,可设置数据项初始值 | | show | Function(form, root) => boolean | 否 | 是否渲染该列,默认渲染 | | layout | Object | 否 | 设置布局模式,可传入[el-row]和[el-col]支持的所有属性 | | renderLabel | Function(h, form, root)/VNode | 否 | 自定义标签内容 | | renderError | Function(h, form, root, {error})/VNode | 否 | 自定义表单校验信息的显示方式 |

Usage Example 使用示例

  1. 基础配置示例
  • column(表格列配置): 数组类型,必传
  • model(表格变量绑定):对象类型,必传
<template>
  <mecc-form
    ref="meccFormRef"
    :model="form"
    :column="column"
    :rules="rules"
    size="small"
    label-width="100px"
    empty-text="--"
  />
</template>

<script>
export default {
  data() {
    return {
      form: {
        name: 'mecc',
        age: 18,
        gender: 'male',
        hobby: ['html', 'css', 'js'],
        time: {
          start: new Date().getTime(),
          end: new Date().getTime()
        },
        skill: [
          {
            name: 'math',
            point: 90
          }
        ]
      },
      rules: {
        name: [{ required: true, message: '请输入姓名', trigger: 'blur' }]
      }
    };
  },
  computed: {
    column() {
      /**
       * 注意:如果不传 render 和 formatter 属性
       * 则需在 <mecc-form> 上通过 :model="form" 绑定
       */
      return [
        // 简易模式
        // 返回数据示例:<span>{{ form.name }}<span>
        {
          prop: 'name',
          label: '姓名'
        },

        // show接收一个方法,根据返回值决定表单项是否显示
        {
          prop: 'custom_hidden',
          label: '自定义隐藏',
          show: (form, root) => false
        },

        // 使用formatter格式化数据
        // 返回数据示例:<span class="gender-icon>{{ genderNameMap[form.gender] }}</span>
        {
          prop: 'gender',
          label: '性别',
          class: 'gender-icon',
          formatter: (form, root) => {
            const genderNameMap = { male: '男生', female: '女生' };
            return genderNameMap[form.gender];
          }
        },

        /**
         * render: 自定义显示元素
         * 可使用v-model进行双向绑定
         * 
         * rules: 可单独设置校验规则
         * renderLabel: 自定义标签文本的内容,参数为 (h, form, root)
         * renderError: 自定义表单校验信息的显示方式,参数为 (h, form, root, {error})
         **/
        {
          prop: 'age',
          renderLabel: (h, form, root) => <span style='color: red;'>年龄</span>,
          renderError: (h, form, root, { error }) => (
            <span style='color: blue'>{error}</span>
          ),
          rules: [
            { required: true, message: '请输入年龄', trigger: 'blur' },
            { type: 'number', min: 1, message: 'hahaha', trigger: 'blur' }
          ],
          render: (h, form, root) => (
            <el-input-number
              v-model={form.age}
              onChange={this.handleChange}
              max={20}
              label='描述文字'
            />
          )
        },

        // 注意Vue中JSX语法的书写规则,部分属性无法传递,需进行包裹后方可传递
        {
          prop: 'hobby',
          label: '兴趣',
          render: (h, form, root) => {
            const options = [
              {
                name: '前端',
                id: 'front',
                children: [
                  {
                    name: 'HTML',
                    id: 'html'
                  },
                  {
                    name: 'JavaScript',
                    id: 'js'
                  },
                  {
                    name: 'CSS',
                    id: 'css'
                  }
                ]
              },
              {
                name: '后端',
                id: 'back',
                children: [
                  {
                    name: 'JAVA',
                    id: 'java'
                  },
                  {
                    name: 'Golang',
                    id: 'golang'
                  },
                  {
                    name: 'Python',
                    id: 'python'
                  }
                ]
              }
            ];
            /**
             * 特别注意
             * 由于 el-cascader 需要传递名称为 'props' 的属性
             * 而在 vue 的 JSX 语法解析中,'props' 属性无法正常传递,所以这里需要特殊处理下
             * 详情可参考 https://www.yuque.com/zeka/vue/vu60wg
             */
            const cascaderProps = {
              options,
              props: {
                checkStrictly: true,
                label: 'name',
                value: 'id',
                multiple: true,
                emitPath: false
              },
              clearable: true,
              filterable: true
            };
            return (
              <el-cascader {...{ props: cascaderProps }} v-model={form.hobby} />
            );
          }
        },
        
        /**
         * 嵌套对象的表单 + 快速布局
         *
         * 配置项:children
         * 数据类型:数组(column)
         * 含义:设置对象的 column列
         *
         * 拓展项:layout
         * 数据类型:对象
         * 含义:引入<el-row>和<el-col>进行布局,接受所有参数
         **/
        {
          prop: 'time',
          label: '活动时间',
          layout: {
            type: 'flex',
            align: 'middle',
            justify: 'start'
          },
          children: [
            {
              prop: 'start',
              label: '开始时间',
              layout: {
                span: 10
              },
              render: (h, form, root) => {
                return <el-date-picker v-model={form.start} />;
              }
            },
            {
              prop: 'end',
              label: '结束时间',
              layout: {
                span: 10,
                offset: 1
              },
              render: (h, form, root) => {
                return <el-date-picker v-model={form.end} />;
              }
            }
          ]
        },

        /**
         * 嵌套数组的表单
         *
         * 配置项:item
         * 数据类型:函数
         * 数据结构:(form, root) => column数组
         * 含义:设置数组每一项的数据结构
         *
         * 拓展项:value
         * 数据类型:any
         * 含义:新增数据项时的默认值
         **/
        {
          prop: 'skill',
          label: '能力评级',
          item: (form, root) => {
            return [
              {
                prop: 'name',
                label: '名称',
                render: (h, form, root) => {
                  return <el-input v-model={form.name} />;
                }
              },
              {
                prop: 'point',
                label: '评分',
                value: 80,
                render: (h, form, root) => {
                  return <el-input-number v-model={form.point} />;
                }
              }
            ];
          }
        }
      ];
    }
  },
  methods: {
    handleChange(val) {
      // 这里同样可以使用 el-form 的 Form Methods,同原生 element-ui 的使用方式相同
      this.$refs.meccFormRef.validateField('age', (err) => {
        if (err) {
          console.error(err);
          return;
        }
        console.log(val);
      });
    }
  }
};
</script>
  1. 模块化开发

当表单的复杂度进一步提高,模块化解耦就成了刚需,@mecc/form 的解决方案:本质上是构造 column 数组。

  • 根组件示例:Demo.vue
<template>
  <mecc-form
    ref="meccFormRef"
    :model="form"
    :column="column"
  />
</template>

<script>
import Location from './Location.js';
import Info from './Info.js';
import mixinUtils from './mixin-utils.js'
export default {
  mixins: [mixinUitls],
  data() {
    return {
      form: {
        name: 'mecc',
        location: '',
        gender: 'male',
        hobby: ['html', 'css', 'js']
      }
    };
  },
  computed: {
    column() {
      return [
        {
          prop: 'name',
          label: '姓名'
        },
        Location.call(this, '地区'),
        ...Info.call(this)
      ];
    }
  }
};
</script>
  • 单模块示例:Location.js
import { v4 as uuidv4 } from 'uuid';

// 生成随机ID,保存在指定变量下
const location = uuidv4()

/**
 * 远程搜索接口
 * @param {string} name 搜索关键字
 */
async function fetchData(str) {
  if (!str) return;
  try {
    const resp = await this.$api.search(str);
    // this.setValue 双向绑定数据,见后文`mixin.js`
    this.setValue(location, resp.data);
  } catch (err) {
    console.error(err);
    this.setValue(location, []);
  }
}

export default function Location(customLabel) {

  // 初始化列表数据
  fetchData();

  return {
    prop: 'location',
    label: customLabel
    render: (h, form, root) => (
      // this.getValue 获取双向绑定的数据
      const optionList = (this.getValue(name) || []).map((opt, idx) => (
        <el-option key={idx} label={opt.label} value={opt.value} />
      ));

      return (
        <el-select
          v-model={form.location}
          filterable
          clearable
          remote
          remote-method={fetchData.bind(this)}
        >
          {optionList}
        </el-select>
    )
  };
}

看过这些示例,相信聪明的你一定发现了,render/renderLabel/renderError 函数中都传递了 h 参数,但大部分的场景下函数体内并没有直接使用,那可不可以去掉呢?

在组件的设计中,我尝试过,在 *.vue 文件中可以正常使用,但是抽离到 *.js 文件的时候就会报错,查阅资料后,在 vue 的官网上有这样一段话:

将h作为createElement的别名是 Vue 生态系统中的一个通用惯例,实际上也是 JSX 所要求的。从 Vue 的 Babel 插件的3.4.0 版本开始,我们会在以 ES2015 语法声明的含有 JSX 的任何方法和 getter 中 (不是函数或箭头函数中) 自动注入const h = this.$createElement,这样你就可以去掉(h)参数了。对于更早版本的插件,如果h在当前作用域中不可用,应用会抛错。

所以,为了兼容更多的情况,我还原了 h 函数,如果你有更好的解决方案,欢迎提PR~

  • 组合模块示例:Info.js
export function Info() {
  return [
      {
        prop: 'gender',
        label: '性别',
        formatter: (form, root) => {
          const genderNameMap = { male: '男生', female: '女生' };
          return genderNameMap[form.gender];
        }
      },
      {
        prop: 'hobby',
        label: '兴趣',
        render: (h, form, root) => {
          const optionList = ['html', 'css', 'javascript'].map(
            return <el-option label={item} value={item} key={item} />
          )
          return <el-select>{optionList}</el-select>
        }
      }
  ]
}
  • 辅助函数:mixin-utils.js
export default {
  data() {
    return { formFetchData: {} };
  },
  methods: {
    setValue(key, val) {
      this.$set(this.formFetchData, key, val);
    },
    getValue(key) {
      return this.formFetchData[key];
    }
  }
};

欢迎使用配套Table组件:@mecc/table