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

imfe-xform-m

v1.1.0

Published

基于vant开发的配置化表单组件

Downloads

4

Readme

imfe-xform-m

基于vant2移动端配置化表单组件,通过内置表单组件和规则以及自定义组件,快速完成较复杂表单开发。

安装

$ npm install -S imfe-xform-m
#or
$ yarn add imfe-xform-m

该组件的peerDependencies

{
  "peerDependencies": {
    "vue": "^2.7.0",
    "vant": "^2.12.48",
    "@vant/area-data": "^1.3.1"
  }
}

使用

组件注册

// main.[ts|js]
import imfexform from "imfe-xform-m";
import "imfe-xform-m/lib/imfe-m-xform.css";
Vue.use(imfexform);

组件使用

<imfe-xform ref="xform" :form-data="formData" :form-config="formSchema" />

组件属性

| 属性名 | 说明 | 类型 | | ----------- | ---------------------------------------- | ------------------- | | form-data | 注入表单中表单项值,会和配置中默认值合并 | Record<string, any> | | form-config | schema 表单配置,详细配置字段使用见下 | xformSchema |

form-data

用户新增编辑表单,该字段不传或传空即可,二次编辑需要从接口获取该表单数据入参。即接口获取的表单数据,来自于用户编辑保存。

所有的字段来自于 schema 中表单项的 key,平铺展示。

export default {
  name: "张三", //  schema中表单项key为name
  sex: "0",
  tumorTime: 1660188452878,
  birthday: "1992-10-20",
  idCard: "340111199210200637",
};

form-config

From props

| 字段 | 说明 | 类型 | | ---------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------ | | formKey | 【必填】表单唯一标识 | string | | title | 表单标题 | string | | description | 表单描述 | string | | style | 表单自定义 style 样式 | object/ Record<string, string> | | passThroughProps | 透传vant-form props,已有相同字段属性会覆盖透传字段 | object/ Record<string, any> | | children | 【必填】表单组 | array/ Array |

Group props

| 字段 | 说明 | 类型 | | ---------------- | ---------------------------------------------------------------------------------------------------------------------------- | ---------------------- | | title | 分组标题 | string | | style | 组模块自定义 style 样式 | Record<string, string> | | passThroughProps | 透传vant-cell-group props,已有相同字段属性会覆盖透传字段 | Record<string, any> | | children | 【必填】表单项 | Array |

Field props

| 字段 | 说明 | 类型 | | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------- | | ui:type | 【必填】当前表单项类型,自定义组件使用 custom-*开头,内建组件见下 | string | | label | 【必填】表单项 Label | string | | key | 【必填】表单项 key,获取表单会取所有表单项的 key 字段集合 | string | | defaultValue | 【必填】表单项默认值,按照当前类型置空'',{},[]等 | any | | placeholder | 占位值 | string | | options | 静态选项值,只针对 select 、checkbox 、 radios 有效且【必填】,选项值依赖联动事件,可预传空数组 | FieldOptions | ((value: any) => FieldOptions) | | rules | 校验规则, 参考vant 表单项的 rules,可自定义 validator、pattern | Array<Partial> | | style | 自定义 style 样式 | Record<string, string> | | meta | 自定义数据 | any | | suffix | 表单项后缀单位,只针对 input 有效 | string | | broadcast | 设置为 true 后会广播当前表单项 change 事件,监听组件(被联动组件)可接受当前表单项的 change 事件和值,用于联动组件场景默认 false | boolean | | withInputValue | 若有值,表示当用户选择该值的选项会出现输入框(通常用于其他选项,用户输入其他值),只针对 checkbox、radios 有效。默认为空即不含输入框。 | any | | breakWrap | label 和表单内容主题是否换行显示。默认 false | boolean | | passThroughProps | 透传 vant 表单项 props,已有相同字段属性会覆盖透传字段 详细见下核心属性说明 | Record<string | 'group' | 'item', string> | | linkEvents | 联动事件行为注册,配合 broadcast 属性,联动用法见下案例 | Array<{key:string; action: (payload: any, vm: any) => void;}> | | visiable | 该表单项是否可见,主要用于联动初始化 | boolean | | disabled | 该表单项是否禁用 | boolean |

表单项配置属性(field prop)核心字段说明

passThroughProps

如果是radioscheckboxgroup包裹的,passThroughProps会使用两个字段分别透传,group字段会透传到组,item会透传到表单项。

例如,checkbox 默认使用 checkboxgroup 包裹,checkbox 和 checkboxgroup 都有 vant 属性,透传分别使用 group 和 item 透传。

passThroughProps:{
	group: {
		// 透传到checkboxgroup
	},
	item:{
		// 透传到checkbox
	}
}

options

只针对多选项表单组件有效,如selectcheckboxradios 且必填。支持数组类型或者返回 promise 的函数

如何从接口数据获取动态 options?

函数可以更好的调用动态options数据,调用数据中心模块或接口获取,promise resolve数据类型为数组。

{
  "ui:type": "checkbox",
   label: "兴趣爱好",
   key: "hobby",
   rules: [{ required: true, trigger: "onBlur" }],
   defaultValue: [1, 2],
   options: () => { //接口数据获取动态options
     return Promise.resolve([
       {
         label: "麻将",
         value: "1",
       },
       {
         label: "骑马",
         value: "2",
       },
       {
         label: "射箭",
         value: "3",
       },
     ]);
 }

组件事件

| 事件名 | 说明 | 回调参数 | | ------ | -------------------------------- | ----------------------------------------------- | | change | 当表单中表单项值发生变化触发事件 | payload: Record<"key"|"value", any> | | failed | 提交表单且验证不通过后触发 | errorInfo: { values: object, errors: object[] } |

组件配置示例

export const formOptions: xformSchema = {
  formKey: 'xform-sample',
  title: 'xform配置化表单样例',
  description: '根据schema描述配置自动化生成表单,支持自定义校验',
  passThroughProps: {
    colon: true
  },
  children: [
    {
      title: '基本信息',
      children:[
        {
          'ui:type': 'input',
          label: '姓名',
          key: 'name',
          defaultValue: '',
          rules: [
            {
              required: true,
              trigger: 'onChange',
              validator: (value: any, rule: any): boolean | Promise<boolean> => {
                if (value.length < 2) {
                  rule.message = '请输入正确的姓名';
                  return false;
                }
                return true;
              }
            }
          ],
          passThroughProps: {
            readonly: true
          },
          style: {
            backgroundColor: #77e8cc,
          }
        }
      ]
    }
  ]
}

表单组件联动示例

疫苗接种,当选择已接种,需要联动新冠疫苗厂家的显隐。

1、疫苗接种的表单项需要增加广播选项broadcast: true,把当前表单项变动广播出去,让需要的的组件接收。

{
'ui:type': 'radio',
label: '疫苗接种',
key: 'vaccine-COVID-19',
broadcast: true,
}

2、疫苗厂家表单项,这时候就可以接受到疫苗接种的广播事件了,使用linkEvents注册对所有接收事件的处理。

linkEvents可以配置多个广播事件监听,key为监听的表单项 key 值(内建组件需要设置 broadcast 为 true,自定义组件也需要按照广播事件规范进行),action为行为注册,入参为监听表单项的值和监听表单组件的实例。

{
'ui:type': 'select',
label: '新冠疫苗厂家',
key: 'vaccine-COVID-19-factory',
options: ['科兴', '智飞'],
linkEvents: [
  {
    key: 'vaccine-COVID-19',
    action: (payload: any, vm: any): void => {
      if (payload.value === '-1') {
        vm.visible = false;
      } else {
        vm.visible = true;
      }
   }
  }
]
}

LinkEvents 联动事件注册

类型 Array

LinkItem

| 字段 | 说明 | 类型 | | ------ | -------------------------------------------------------------------- | ------------------------------- | | key | 监听表单项的 key,自定义组件需要提前注册到事件总线,注册方式见下 | string | | action | 行为注册,入参为监听的表单项的荷载值 payload 和监听表单组件的实例 vm | (payload: any, vm: any) => void |

自定义组件的使用

表单支持研发增加自定义复杂业务表单组件,其简单原理为注册用户自定义表单组件到 vue 全局组件即可。

1、在components/目录下新增自定义组件目录xform-custom(可按业务和场景自定义任意目录名)

2、在入口文件 main.js,注册该目录下的组件到全局或利用 webpack 按路径批量注册(推荐)

// main.js
const xformCustom = require.context(
  "src/components/xform-custom",
  true,
  /\.vue$/
);
[xformCustom].forEach((formFiles) => {
  formFiles.keys().forEach((filePath) => {
    const fileConfig = formFiles(filePath);
    const fileName = fileConfig.default.name;
    Vue.component(fileName, fileConfig.default || fileConfig);
  });
});

3、自定义组件请使用imfe-custom-*开头命名组件

4、schema文件中配置该组件省略掉imfe,直接使用custom-*即可

增加自定义组件目录,项目简化结构示意如下

src/
├── App.vue
├── assets
│   └── logo.png
├── components
│   └── xform-custom
│       └── imfe-custom-faceid.vue
├── main.js

schemafield使用自定义组件

// schema
export default {
	...
  {
    "ui:type": "custom-faceid",
    label: "人脸识别",
    key: "faceId",
    defaultValue: "",
    broadcast: true, // 是否广播change值。可选。
    LinkEvents: [], // 如何接受其他表单项change值。可选。
    meta: {
    	//自定义组件数据
    },
   }
   ...
}

xform 自定义 vue 组件开发模板(重要)

核心是要模板注入表单组件提供的 Mixin customMixin,其提供内建自定义组件的值和方法。

<template>
  <div class="imfe-xform-custom-test">
    <van-field
      v-model="fieldValue"
      :label="formItem.label"
      @input="emitFormChange"
    />
    <div class="custom-test-msg">{{ customMeta.msg }}</div>
  </div>
</template>

<script>
import { defineComponent } from "vue";
import { customMixin } from "imfe-xform-m";
export default defineComponent({
  name: "imfe-custom-test",
  mixins: [customMixin],
});
</script>

customMixin内建资源

| 自定义组件 Mixin | | | ------------------- | ------------------------------------------- | | this.formItem | 约定为 schema 中当前表单项配置 | | this.customMeta | 约定为配置项中 meta 值 | | this.fieldValue | 约定为当前表单项值 | | this.emitFormChange | 约定为表单项 change 或 input 等事件监听函数 |

export const customMixin = {
  props: {
    // formItem,schema中当前表单项配置
    formItem: {
      type: Object,
      required: true,
    },
  },
  computed: {
    // customMeta,配置项中meta值
    customMeta() {
      return this.formItem.meta || {};
    },
  },
  watch: {
    // fieldValue,当前表单项值
    "$attrs.formModel"(newFormModel) {
      this.fieldValue = newFormModel[this.formItem.key];
      this.emitFormChange(this.fieldValue);
    },
  },
  mounted() {
    // 联动配置使用linkevents源码,研发无需关心
    this.formItem.linkEvents &&
      this.formItem.linkEvents.forEach((item) => {
        EventBus.$on(item.key, (payload) => {
          item.action(payload, this);
        });
      });
  },
  beforeDestroy() {
    // 自动销毁eventbus
    EventBus.$off();
  },
  methods: {
    // 表单项change或input事件监听函数
    emitFormChange(value) {
      const { key, broadcast } = this.formItem;
      const payload = { key, value };
      // 表单项联动,广播事件
      broadcast && EventBus.$emit(key, payload);
      // 表单变动,触发表单收集事件
      fieldChangeHandler(payload);
    },
  },
};

TypeScript Types

export type FormDefValue = string | number | any[];
export type FieldOptions = Array<{ label: string; value: any }> | Array<string>;
export type FieldDynamicOptions = FieldOptions | (() => Promise<FieldOptions>);
interface FieldRules {
  required: boolean;
  message: string | ((value: any, rule: any) => string);
  pattern: RegExp;
  trigger: "onSubmit" | "onBlur" | "onChange";
  validator: (value: any, rule: any) => boolean | Promise<boolean>;
  formatter: (value: any, rule: any) => any;
}
interface LinkItem {
  key: string | string[];
  action: (payload: any, vm: any) => void;
}
interface FormDef {
  "ui:type": string; // 当前表单项名称
  label: string;
  key: string; // 表单项唯一标识,自动会加上表单key作为namespace安全隔离
  defaultValue?: any; // 默认值
  visiable?: boolean; // 是否可见
  disabled?: boolean; // 是否禁用
  placeholder?: string;
  options?: FieldDynamicOptions; // 选项
  rules?: Array<Partial<FieldRules>>; // 校验规则, 参考vant表单项的rules
  style?: Record<string, string | number>;
  meta?: any; // 自定义表单项的数据携带,非内建表单项使用
  suffix?: string; // 后缀单位
  withInputValue?: any; // 带输入框信息
  breakWrap?: boolean; // 是否label和表单强制换行显示
  passThroughProps?: Record<string, any>; // vant表单项透传属性,透传的vant属性如果和表单项的属性重名,透传属性将不会生效,如label、placeholder等
  broadcast?: boolean; // 广播当前表单项change事件,事件名为当前表单项key值,用于联动组件场景
  linkEvents?: Array<LinkItem>; // 联动事件行为注册
}
export interface FieldProps extends FormDef {
  siblings?: Array<FormDef>; // 默认一行一个表单,如果siblings有值,则表示同行多个表单项
}
export interface GroupProps {
  title?: string; // 组标题
  style?: Record<string, string | number>; // 组样式
  children: Array<FieldProps>; // 子表单项
  passThroughProps?: Record<string, any>;
}
export interface xformSchema {
  formKey: string; // 表单唯一标识,
  title?: string; // 表单标题
  description?: string; // 表单描述
  style?: Record<string, string>; // 表单样式
  passThroughProps?: Record<string, any>;
  children: Array<GroupProps>;
}

内建组件

input

输入框

{
  'ui:type': 'input',
  label: '',
  key: '',
  defaultValue: '',
  placeholder:'',
  rules: [{}],
  suffix: '',
},

radio

单选

{
  'ui:type': 'radio',
  label: '',
  key: '',
  defaultValue: '',
  withInput: false,
  options:[{ label: '', value: '' }],
  rules: [{}],
  passThroughProps:{
  group: {
      // 透传到radiogroup
    },
    item:{
      // 透传到radio
    }
  }
},

checkbox

复选框

{
  'ui:type': 'checkbox',
  label: '',
  key: '',
  defaultValue: '',
  withInput: false,
  options:[{ label: '', value: '' }],
  rules: [{}],
  passThroughProps:{
    group: {
      // 透传到checkboxgroup
    },
    item:{
      // 透传到checkbox
    }
  }
},

select

下拉滑动选择器

{
  'ui:type': 'select',
  label: '',
  key: '',
  defaultValue: '',
  options:[''],
  rules: [{}],
},

date

日期选择

{
  'ui:type': 'date',
  label: '',
  key: '',
  defaultValue: '',
  rules: [{}],
},

area

城市选择,带详细地址填写。

{
  'ui:type': 'area',
  label: '',
  key: '',
  defaultValue: '',
  rules: [{}],
},

rate

评分

{
  'ui:type': 'rate',
  label: '',
  key: '',
  defaultValue: '',
  rules: [{}],
},

slider

滑动选择器

{
  'ui:type': 'slider',
  label: '',
  key: '',
  defaultValue: '',
  rules: [{}],
  passThroughProps:{}
},

stepper

步进器

{
  'ui:type': 'stepper',
  label: '',
  key: '',
  defaultValue: '',
  rules: [{}],
  passThroughProps: {}
},

switch

开关

{
  'ui:type': 'switch',
  label: '',
  key: '',
  defaultValue: '',
  rules: [{}]
},

uploader

文件上传

{
  'ui:type': 'uploader',
  label: '',
  key: '',
  defaultValue: '',
  rules: [{}],
  passThroughProps: {}
},

title

标题组件

{
  'ui:type': 'title',
  label: '',
  key: '',
  defaultValue: '',
},

业务标准组件

std-checkbox

复选框

{
  'ui:type': 'checkbox',
  label: '',
  key: '',
  defaultValue: '',
  meta: {
    span: 8,
    options: [{ label: '', value: '' }],
    withInput: false
  }
},

std-radios-checkbox

二值单选+复选框

{
    'ui:type': 'custom-radios-checkbox',
    label: '二值单选-复选框',
    key: '',
    rules: [{ required: true, trigger: 'onBlur' }],
    defaultValue: {
      radios: '-1',
      checkbox: {}
    },
    meta:{
      radios: {
        options: [
          {
            label: '无',
            value: '-1'
          },
          {
            label: '有',
            value: '1'
          }
        ]
      },
      checkbox: {
        span: 12,
        options: [{ label: '', value: '' }],
        withInput: true
    }
}

std-radios-textarea

二值单选+文本录入

{
          "ui:type": "std-radios-textarea",
          label: "二值单选-文本录入",
          key: "",
          defaultValue: {
            radios: "",
            input: "",
          },
          meta: {
            // 业务组件自定义数据字段
            radios: {
              options: [
                {
                  label: "无",
                  value: "-1",
                },
                {
                  label: "有",
                  value: "1",
                },
              ],
            },
            textarea: {
              placeholder: "请输入",
            },
          },
        },

std-dynamic-fields-type1

动态新增表单项组(input-date)

{
          "ui:type": "std-dynamic-fields-type1",
          label: "动态新增表单项组",
          key: "",
          rules: [{ required: true, trigger: "onBlur", message: "必填" }],
          meta: {
            // 业务组件自定义数据字段
            radiosOptions: [
              {
                label: "无",
                value: "-1",
              },
              {
                label: "有",
                value: "1",
              },
            ],
            addText: "添加选项",
            formItems: {
              input: {
                label: "名称",
                placeholder: "请输入名称",
                passThroughProps: {
                  maxlength: 10,
                },
              },
              date: {
                label: "时间",
                placeholder: "请选择时间",
                passThroughProps: {
                  "min-date": new Date("1950-01-01"),
                },
              },
            },
          },
          defaultValue: {
            exsist: "-1",
            value: [],
          },
        },