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

相關文章
相關標籤/搜索