vue3 根据json生成表单简单实现 主要是基于render函数和tsx

json生成表单主要是解决一些业务上的烦恼,能够用json来描述一个表单组件,话很少说 上代码html

//首先思考 json怎么来描述一个表单
    //首先 表单控件应该有一个名字 input button select等等
    //这里咱们就描述了一个input的控件
    let obj = {
        type:'input'
    }
    //而后光渲染没用 咱们须要给他加上布局 双向绑定 监听事件 而后绑定字段 传给后台作交互 引伸一下 把这//个对象能够扩展一下
    obj={
        type: 'input',//是什么控件
        name: 'cccc',//字段是什么
        value: '',//双向绑定的值
        label: '2222',//在表单里面他的label
        props: { //须要传递下去的props
          placeholder: '11111',
        },
        col: { //布局
          span: 4,
        },
        on:{ //事件监听
            change:(v:any)=>{
                console.log(v)
            }
        }
      }
      //这样通过咱们的处理 应该就描述了一个input组件 可是实际应用中 你应该须要一次描述多个 那他的数据格
//式就应该是
   //const rule = [{...obj},{这里继续描述下一个}]
   //描述完了 怎么渲染呢 看文档!!!! https://www.vue3js.cn/docs/zh/guide/render-function.html
   
复制代码

image.png

//那咱们就应该是
    {vm.rule.map((i: IRuleItem) => {
      return (
       <a-col span={i.col?.span}> <a-form-item label={i.label}>{vm.getRuleItem(i)}</a-form-item> </a-col>
      ;
    })}
复制代码

基本上到这个地方 组件的模型就已经出来了 可是他也基本上不能知足需求 只是一辆玩具车 怎么来拓展咱们的功能呢?怎么让他支持自定义组件呢 看文档!!!vue

image.png

image.png 同理可证 咱们的自定义组件 能够经过模仿vue.compoent的注册来实现node

//插件代码
import { Component } from 'vue';
import { Vue } from 'vue-class-component';
import CForm from './corsrc/CForm';
interface Iplu {
  install: any
  component: (name: string, component: Component) => void
  newComponent: { [x: string]: Component; }
  // testArr:{}
}
interface IPluVue extends Vue {
  [x: string]: any
}
const plu: Iplu = {
  install(Vue: IPluVue, op: any) {
    Vue.component('CForm', CForm);
  },
  component(name: string, component: Component) {
      //这个就是模拟的组件注册 每次都是渲染的vnode 同时利用{} 的 key-value的结构特色 来储存他
     
    this.newComponent[name] = component;
  },
  newComponent: {},
};
export default plu;

复制代码
/** 上面说了自定义组件的实现 可是若是是基本的表单功能 我还要一个一个去注册吗?太麻烦了吧 我门不是应该解决麻烦吗 而后我要去找答案 怎么找? 看文档!!! */
复制代码

image.png

image.png

//这里提到了一个api resolveComponent(string) 返回一个已经注册组件 那不就万事大吉了 
//也就是说 el-input a-input会被渲染成组件 而不是html标签 
//同理可证 咱们能够在这个插件里面 写上一些默认的 经常使用的form组件 我用antd 就是
interface defaultCompoentObj {
  input: string
  datePicker: string
  [x: string]: any
}
const index: defaultCompoentObj = {
  input: 'aInput',
  datePicker: 'aDatePicker',
};
export default index;
复制代码

这个就是实现了 默认组件还有一些自定义组件的渲染还有注册的功能 可是这个时候 他只是一个雏形 依然仍是玩具车react

//看到上面的代码不少大佬 就会明白 下拉框 不是一个json能描述的了的 而是 须要select option来配合的
//怎么办? 本身写啊 本身用的你的ui库去封装一个下拉 而后放到默认的表单组件里面
interface defaultCompoentObj {
  input: string
  datePicker: string
  [x: string]: any
}
import select from '@/form/corsrc/CForm';
const index: defaultCompoentObj = {
  input: 'aInput',
  datePicker: 'aDatePicker',
  select,
};
export default index;
//vnode和全局注册的组件都是能够找到的 这样就解决了一些不方便的问题 小伙伴们 不就能够拿去二次开发了吗
复制代码

这里主要的实现思路 就是默认有一个对象{} 经过key-value的形式来储存组件的名字 例如 input:a-input 这样就是实现了 第一步 {type:"input"} 这里的input其实就是经过默认的对象代理到的 a-input 那咱们也能够经过编写一个select组件 来实现 select下拉的功能git

而后自定义组件是另外一个对象 每次判断type是否在默认对象里面 若是在直接渲染 若是不在判断是否是在自定义组件的对象里面 若是也不在 直接报错,若是在的话 你注册的是这样一个对象{key:VNode} 而后经过render函数 直接渲染VNodegithub

上完整代码 我是用的antd作的二次开发json

import { defineComponent, h, reactive, VNode, resolveComponent } from 'vue';
import { Vue } from 'vue-class-component';
import { IRuleItem } from '../types/ruleType';
import { setDefaultCompoent, setRuleItemColSapn } from '@/form/utils/utils';
interface CForm extends Vue {
  rule: []
  formModel: { [x: string]: any; }
  getRuleItem: (i: IRuleItem) => VNode
  returnFormModel: () => void
}
const CForm = defineComponent({
  name: 'CForm',
  props: {
    rule: {
      type: Array,
      default: () => {
        return [];
      },
    },
    value: {
      type: Object,
      default: () => {
        return {};
      },
    },
  },
  setup(props, ctx) {
    const formModel: CForm['formModel'] = reactive({});
    //Api func 这里用一下方法处理 数据
    const funcObj = {
      getValue: (key: string) => { //根据Key获取函数
        return formModel[key];
      },
      getFormData: () => { //获取表单数据 主要是用做提交
        return formModel;
      },
    };
    const CApi = reactive(props.value);
    CApi.getValue = funcObj.getValue;
    CApi.getFormData = funcObj.getFormData;
    ctx.emit('update:valie', CApi);
    /** * 根据rule的item来生成组件 * @param i * @returns */
    if (props.rule.length) {
      const rule: IRuleItem[] = props.rule as IRuleItem[];
      rule.forEach((i: IRuleItem) => {
        formModel[i.name] = i.value;
      });
    }
    function getRuleItem(i: IRuleItem) {
      return h(resolveComponent(setDefaultCompoent(i.type)), {
        value: formModel[i.name],
        ...i.props,
        ...i.on,
        'onUpdate:value': (v: any) => {
          formModel[i.name] = v;
        },
      });
    }
    return {
      formModel,
      getRuleItem,
    };
  },
  /** * * @param vm :model="formState" :label-col="labelCol" :wrapper-col="wrapperCol" * @returns */
  render(vm: CForm) {
    // setRuleItemColSapn(i.col?.span)

    return (
      <div class="CForm"> <a-form model={vm.formModel}> <a-row> {vm.rule.map((i: IRuleItem) => { return ( <a-col span={i.col?.span}> <a-form-item label={i.label}>{vm.getRuleItem(i)}</a-form-item> </a-col> ); })} </a-row> </a-form> </div>
    );
  },
});
export default CForm;
复制代码

另外有vue3一块儿学习的小伙伴也能够喊我 我学不动了 求指教 有啥好的解决方法也能够喊我一块儿 我感受我写的好丑 主要是只是提供一个思路 抽象一下平常的业务组件 用数据去描述 解决问题 源码地址 github.com/q969210177/…api

自定义的组件和基础的表单组件的判断已经作完了 下一步是用json来描述form的配置markdown

推荐一个大佬基于vue2的json生成表单 你们也能够一块儿学一下 www.form-create.com/v2/ 也是看到大佬作的 我对于组件渲染有了本身的理解antd

相关文章
相关标签/搜索