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

@hxyfe/vs-form

v1.0.0

Published

基于 Vue 的使用 js 对象 进行配置生成的表单,主要适用于移动端

Downloads

1

Readme

Form json 配置表单

介绍

基于 Vue 的使用 js 对象 进行配置生成的表单,主要适用于移动端

该表单的特点如下:

  1. 可以支持任意的表单组件库,例如:vant、vux甚至自建组件库等
  2. 表单内部未内置任何表单项

由于和表单项松耦合,所以表单项必须实现 v-model ,如果没有实现,则无法正常管理该表单项

作者本人使用 VsForm 的原因:

  1. 提供表单项的联动,只需简单配置就能实现
  2. 配置直接生成表单,不用写一堆臃肿的模板
  3. 配置支持设置默认属性,使得能够统一表单项的默认设置
  4. 支持配置校验规则,不用写一堆 if else 来手动校验
  5. 数据驱动视图,只需要修改配置对象,则会自动刷新UI
  6. 支持在指定位置渲染 slot
  7. 通过 v-model 直接拿到/设置 表单的值
  8. 作者还在回忆...

由于内部没有内置表单项,下面演示代码均是配合组件库 vant 编写。(vant 不会告我侵权吧。。。)

使用

安装

NPM

npm i --save vs-form

YARN

yarn add vs-form

简单使用

在最简单的情况下,无需其他配置就可以使用

// main.js
import VsForm from 'vs-form';
// Vant 可以换成任意的组件库,或者压根就不引入组件库而使用自定义组件
import Vant, { Toast } from 'vant';
Vue.use(Vant);

// 设置校验不通过提示方法
VsForm.showError = (errors) => {
  // 弹框提示未通过原因
  Toast(errors[0].message)
}

Vue.use(VsForm);
<vs-form v-model="form" ref="form" :fieldsConfig="fieldsConfig" class="gc-mb60">
  <template slot="introduction">
    <div>我是 slot introduction</div>
  </template>
</vs-form>
// 由于没有做其他配置,所以配置中 type 就是表单项组件名  
// 其中 slot 是特殊的,代表这里需要渲染一个 具名slot, slot 名是配置项中的 key  
export default {
  data() {
    return {
      // 如果需要绑定事件,则需要传 this 给配置数组
      fieldsConfig: [
        {
          label: '你的名字',
          key: 'name',
          type: 'van-field',
          props: {
            rules: [{ required: true, message: '请输入姓名' }],
          },
        },
        {
          label: '费用科目',
          key: 'costAccount',
          type: 'van-picker',
          props: {
            required: true,
            columns: ['杭州', '宁波', '温州', '绍兴', '湖州', '嘉兴', '金华', '衢州'],
          },
        },
        {
          key: 'introduction',
          type: 'slot',
          // 只有 vip 才配拥有这个 slot
          ifRender(form, config) {
            let render = false;
            if (form.name === 'vip') {
              render = true;
            }

            return render;
          },
        },
      ],
      form: {},
    };
  },
  methods: {
    // 校验表单
    validate() {
      return this.$refs.form.validate();
    },
  },
};

自定义 typeMap

VsForm 还有一个静态属性 typeMap ,这个映射表可以指定配置中的 type 指向的是什么组件。
同时还可以对该组件进行默认配置,例如给所有的 textarea 设置一个最大长度

// main.js
import VsForm from 'vs-form';
import typeMap from '[你的自定义 typeMap 存放位置]';

Vue.use(VsForm, typeMap);
// typeMap.js

// 表单项映射表
export default {
  // 普通输入框
  input: {
    // 指定实际的组件名
    // 使用懒加载的方式加载
    // 此处直接加载了组件,也可以指定一个已经注册了的组件名
    // 例如:component: 'van-field'
    component: () => {
      import('vant/lib/field/style');
      return import('vant/lib/field');
    },
    props: {},
  },

  // 进度条
  progress: {
    // 指定实际的组件名
    component: () => {
      import('vant/lib/progress/style');
      return import('vant/lib/progress');
    },
    props: {},
  },

  // 开关
  switch: {
    // 指定实际的组件名
    component: () => {
      import('vant/lib/switch-cell/style');
      return import('vant/lib/switch-cell');
    },
    props: {},
  },

  // 多行输入
  textArea: {
    // 指定实际的组件名
    component: () => {
      import('vant/lib/field/style');
      return import('vant/lib/field');
    },
    props: {
      rows: '2',
      autosize: true,
      type: 'textarea',
      maxlength: '50',
      'show-word-limit': true,
    },
  },

  // 数字输入
  inputNumber: {
    // 指定实际的组件名
    component: () => {
      import('vant/lib/field/style');
      return import('vant/lib/field');
    },
    props: {
      type: 'number',
    },
  },

  // 图片选择
  imgPic: {
    // 指定实际的组件名
    component: () => {
      import('vant/lib/uploader/style');
      return import('vant/lib/uploader');
    },
    props: {},
  },

  // 纯文本展示
  cell: {
    component: () => {
      import('vant/lib/cell/style');
      return import('vant/lib/cell');
    },
    // 动态 props
    // props 取值顺序是:typeMap.props -> item.props -> typeMap.getProps() -> item.getProps()
    // 后面对象的同名属性会覆盖前面的对象的同名属性,使用的Object.assign实现
    getProps(form, config) {
      return {
        title: config.label || config.key,
      };
    },
  },
};

对表单进行校验

可以通过在配置参数中的props参数里面传入rules进行表单表单项的规则配置,表单校验采用了 async-validator 作为底层,规则与之一致。

表单支持使用插件注册处理校验结果的方法,此处未做演示。

<vs-form ref="form" v-model="form" :fields-config="fieldsConfig" />
<div>
  <p v-if="errors.length > 0">我是校验不通过的提示</p>
  <p style="{ color: red }" v-for="(err, i) in errors" :key="err + i">
    {{ err.message }}
  </p>
</div>

<div @click="submit" type="default">提交</div>
export default {
  data() {
    return {
      fieldsConfig: [
        {
          label: '请假事由',
          key: 'leaveReason',
          type: 'input',
          props: {
            required: true,
            rules: [
              { type: 'string', required: true, message: '请假事由必填' },
              {
                type: 'string',
                message: '请假事由不能小于6个字符',
                pattern: /\w{6,}/,
              },
            ],
          },
          // 事件绑定
          on: {
            input() {
              console.log('input');
            },
            change() {
              console.log('change');
            },
          },
        },
      ],
      form: {},

      errors: [],
    };
  },

  methods: {
    submit() {
      this.$refs.form.validate().then(
        () => {
          console.log('校验通过');
          this.errors = [];
        },
        err => {
          this.errors = err;
          Toast({ message: err[0].message });
        }
      );
    },
  },
};

API

Props

| 参数 | 说明 | 类型 | 默认值 | | --------------- | ------------------ | ---------- | ------ | | v-model (value) | 当前表单的值 | object | - | | fieldsConfig | 当前表单的配置参数 | config[] | - |

表单赋值采用的合并操作,并不是替换操作,类似 Object.assign ,所以不会删除 val 中没有的键名的值
例如表单值为: { a: 2, b: 1 }, val 值为 { a: 1 },则赋值后的结果为 { a: 1, b: 1 }
如果需要清空值,请使用 reset()

config

| 参数 | 说明 | 类型 | 默认值 | | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- | ------ | | type | 表单项的类型/表单项的名称 | string | - | | key | 当前表单项绑定的属性名/slot的具名名称 | string | - | | on | 当前表单项绑定的事件(需要自行处理 this 指向) | object: {event} | - | | nativeOn | .native 绑定的事件 | object: {event} | - | | component | 表单项的标签名/表单项(直接引入) | VNode | string | - | | label | 表单项展示的 label 名(如果必填项未提供校验message则会使用这个 label 进行提示) | string | - | | required | 表单项是否必填(也可以写在 rules 里面)(ui部分需要自行处理) | boolean | - | | others | 其他支持 jsx 的一些属性,其中 on / nativeOn / props 被移除 | object | - | | props | 表单项的配置参数,直接透传给对应表单项 | object | - | | getProps | 表单项的动态参数计算方法,计算出结果后和上面的 props 合并 | function | - | | ifRender | 表单项的是否渲染计算方法,根据计算出的结果决定是否渲染表单项,表单联动的实现机制 | function | - | | $$ifRender | 表单项是否渲由上面方法计算出的结果 | function | - |

getProps({...form}, config) 的入参为:form 的当前值 和 当前表单项当时的配置值(可能前面已经被动态修改了)

ifRender({...form}, config) 的入参为:form 的当前值 和 当前表单项当时的配置值(可能会由于其他表单项的改变而改变)

props 取值顺序是:typeMap.props -> item.props -> typeMap.getProps() -> item.getProps()
后面对象的同名属性会覆盖前面的对象的同名属性,使用的 Object.assign 实现

type 为 slot 类型的表单项,其实是一个 slot 占位,slot 名与 key 或者 name 属性的值相同

Events

VsForm 使用 v-model 进行值管理,所以会冒泡 input 事件
其他表单项事件由各个表单项确定,监听事件需要自行定义在配置项中

| 事件 | 说明 | 回调参数 | | ----- | ------------------ | ------------------------------ | | input | 表单内容变化时触发 | value: object (当前表单的值) |

方法

通过 ref 可以获取到 Form 实例并调用实例方法

| 方法名 | 说明 | 参数 | 返回值 | | --------- | ------------------------------ | ------------------------------------------------- | ---------------- | | validate | 校验整个表单 | noTips: Boolean(是否需要弹窗提示错误信息) | promise: Promise | | reset | 重置表单值为指定的值 | val: Object | - | | refreshUI | 强制重新计算配置项,进行UI刷新 | force: boolean (true:无论是否有更新,强制刷新) | - |

理论上你永远都不需要使用 refreshUI 方法,如果你遇到了需要使用的场景,请联系我

Q&A

  1. Q:为什么没有处理 CSS?A:移动端一般都是自定义样式,使用者自行定义一套全局样式即可。
  2. Q:为什么使用 v-model 来实现数据绑定?A:符合 vue 使用者的习惯,而且可以做到和表单项解耦。
  3. Q:表单项的值是复杂对象怎么办?A:复杂对象会被深度监听,使用者需要自己注意不要死循环,其他和单值没区别。
  4. ...