React JSON Schema Form

最近在用ant design做后臺(tái)管理系統(tǒng),表單真是蛋疼的存在蘑拯。

下面貼一段截自與ant design官網(wǎng)的代碼

import { Form, Icon, Input, Button } from 'antd';
const FormItem = Form.Item;

function hasErrors(fieldsError) {
  return Object.keys(fieldsError).some(field => fieldsError[field]);
}

class HorizontalLoginForm extends React.Component {
  componentDidMount() {
    // To disabled submit button at the beginning.
    this.props.form.validateFields();
  }
  handleSubmit = (e) => {
    e.preventDefault();
    this.props.form.validateFields((err, values) => {
      if (!err) {
        console.log('Received values of form: ', values);
      }
    });
  }
  render() {
    const { getFieldDecorator, getFieldsError, getFieldError, isFieldTouched } = this.props.form;

    // Only show error after a field is touched.
    const userNameError = isFieldTouched('userName') && getFieldError('userName');
    const passwordError = isFieldTouched('password') && getFieldError('password');
    return (
      <Form layout="inline" onSubmit={this.handleSubmit}>
        <FormItem
          validateStatus={userNameError ? 'error' : ''}
          help={userNameError || ''}
        >
          {getFieldDecorator('userName', {
            rules: [{ required: true, message: 'Please input your username!' }],
          })(
            <Input prefix={<Icon type="user" style={{ fontSize: 13 }} />} placeholder="Username" />
          )}
        </FormItem>
        <FormItem
          validateStatus={passwordError ? 'error' : ''}
          help={passwordError || ''}
        >
          {getFieldDecorator('password', {
            rules: [{ required: true, message: 'Please input your Password!' }],
          })(
            <Input prefix={<Icon type="lock" style={{ fontSize: 13 }} />} type="password" placeholder="Password" />
          )}
        </FormItem>
        <FormItem>
          <Button
            type="primary"
            htmlType="submit"
            disabled={hasErrors(getFieldsError())}
          >
            Log in
          </Button>
        </FormItem>
      </Form>
    );
  }
}

const WrappedHorizontalLoginForm = Form.create()(HorizontalLoginForm);

ReactDOM.render(<WrappedHorizontalLoginForm />, mountNode);

代碼看的是真心累,各種方法屬性以及html混合在一起,第一眼就不想看了盛霎。

思考:有沒有方便簡(jiǎn)單的方式來定義一個(gè)表單,像下面這樣的:

{
    "userName":{
        required:true,
        type:"string",
        message:{
          required:"Please input your username!"
        }
    },
    "password":{
        required:true,
        type:"string",
        message:{
          required:"Please input your Password!"
        }
    }
}

在公共代碼庫中找了下耽装,還真有類似的類庫愤炸, react-jsonschema-form;這個(gè)庫只需要提供2份配置即可生成出界面掉奄,一份是json schema规个,一份是ui schema。真是便利的表單,配置即代碼诞仓。

下面來看下簡(jiǎn)單的配置:

{
  "title": "A registration form",
  "description": "A simple form example.",
  "type": "object",
  "required": [
    "firstName",
    "lastName"
  ],
  "properties": {
    "firstName": {
      "type": "string",
      "title": "First name"
    },
    "lastName": {
      "type": "string",
      "title": "Last name"
    },
    "age": {
      "type": "integer",
      "title": "Age"
    },
    "bio": {
      "type": "string",
      "title": "Bio"
    },
    "password": {
      "type": "string",
      "title": "Password",
      "minLength": 3
    },
    "telephone": {
      "type": "string",
      "title": "Telephone",
      "minLength": 10
    }
  }
}
{
  "firstName": {
    "ui:autofocus": true,
    "ui:emptyValue": ""
  },
  "age": {
    "ui:widget": "updown",
    "ui:title": "Age of person",
    "ui:description": "(earthian year)"
  },
  "bio": {
    "ui:widget": "textarea"
  },
  "password": {
    "ui:widget": "password",
    "ui:help": "Hint: Make it strong!"
  },
  "date": {
    "ui:widget": "alt-datetime"
  },
  "telephone": {
    "ui:options": {
      "inputType": "tel"
    }
  }
}

json schema可以放在公共服務(wù)器热鞍,后端也可以使用同樣的json schema來驗(yàn)證數(shù)據(jù)的合法性疗琉,同樣的驗(yàn)證方式镇防,同樣的錯(cuò)誤消息股囊,真實(shí)簡(jiǎn)單實(shí)用。

但是很快問題就來了:

  1. 當(dāng)表單的布局很復(fù)雜的時(shí)候怎么辦谍婉;比如firstName和lastName一行舒憾,使用一個(gè)fieldSet來包裹,其他使用默認(rèn)的配置生成表單穗熬。
  2. 當(dāng)需要擴(kuò)展功能的時(shí)候珍剑,比如我需要一個(gè)顯示/隱藏的功能;當(dāng)firstName和lastName都填寫之后才顯示其他字段等等死陆。
  3. 當(dāng)我一些動(dòng)態(tài)數(shù)據(jù)的需求的時(shí)候招拙,比如select的數(shù)據(jù)是從接口獲取并填充到組件的;又或者隱藏/顯示數(shù)組的子項(xiàng)等等措译。

基于上面的問題别凤,怎么解決呢?

json schema的定義:

{
  "definitions": {
    "address": {
      "type": "object",
      "properties": {
        "street_address": {
          "type": "string"
        },
        "city": {
          "type": "string"
        },
        "state": {
          "type": "string"
        }
      },
      "required": [
        "street_address",
        "city",
        "state"
      ]
    },
    "node": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "children": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/node"
          }
        }
      }
    }
  },
  "type": "object",
  "properties": {
    "billing_address": {
      "title": "Billing address",
      "$ref": "#/definitions/address"
    },
    "shipping_address": {
      "title": "Shipping address",
      "$ref": "#/definitions/address"
    },
    "tree": {
      "title": "Recursive references",
      "$ref": "#/definitions/node"
    }
  }
}

ui schema的定義

{
  "ui:order": [
    "shipping_address",
    "billing_address",
    "tree"
  ]
}
【shipping_address】字段的生成結(jié)果

首先讓我們來看一看表單中的每一個(gè)項(xiàng)由什么組成领虹。

  • 首先這里定義了一個(gè)fieldset规哪,顯示為Shipping address
  • 其次這里的數(shù)據(jù)結(jié)構(gòu)為:Object -> [string,string,string],對(duì)應(yīng)的表單顯示為:ObjectField-> [ FieldTemplate->BaseInput, FieldTemplate->BaseInput, FieldTemplate->BaseInput ];
react的組件樹

有沒有可能定義出ObjectField-> RowTemplate->[ ColTemplate->FormItemTemplate->BaseInput, ColTemplate->FormItemTemplate->BaseInput, ColTemplate->FormItemTemplate->BaseInput ]這樣的結(jié)構(gòu)塌衰;這里要定義多模板诉稍,只能自定義Field來滿足需求,但是模板不能夠復(fù)用最疆,很蛋疼杯巨。當(dāng)然還有很多問題需要解決,比如ColTemplate中的span努酸、pull和push如何來定義等服爷。

針對(duì)以上的問題,我們來修改一下結(jié)構(gòu)获诈。

修改后的表單結(jié)構(gòu)

fx-schema-form

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末仍源,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子舔涎,更是在濱河造成了極大的恐慌笼踩,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亡嫌,死亡現(xiàn)場(chǎng)離奇詭異嚎于,居然都是意外死亡桶至,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門匾旭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人圃郊,你說我怎么就攤上這事价涝。” “怎么了持舆?”我有些...
    開封第一講書人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵色瘩,是天一觀的道長。 經(jīng)常有香客問我逸寓,道長居兆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任竹伸,我火速辦了婚禮泥栖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘勋篓。我一直安慰自己吧享,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開白布譬嚣。 她就那樣靜靜地躺著钢颂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拜银。 梳的紋絲不亂的頭發(fā)上殊鞭,一...
    開封第一講書人閱讀 51,182評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音尼桶,去河邊找鬼操灿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛泵督,可吹牛的內(nèi)容都是我干的牲尺。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼幌蚊,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼谤碳!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起溢豆,我...
    開封第一講書人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤蜒简,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后漩仙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體搓茬,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡犹赖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了卷仑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片峻村。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖锡凝,靈堂內(nèi)的尸體忽然破棺而出粘昨,到底是詐尸還是另有隱情,我是刑警寧澤窜锯,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布张肾,位于F島的核電站,受9級(jí)特大地震影響锚扎,放射性物質(zhì)發(fā)生泄漏吞瞪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一驾孔、第九天 我趴在偏房一處隱蔽的房頂上張望芍秆。 院中可真熱鬧,春花似錦翠勉、人聲如沸浪听。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽迹栓。三九已至,卻和暖如春俭缓,著一層夾襖步出監(jiān)牢的瞬間克伊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來泰國打工华坦, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留愿吹,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓惜姐,卻偏偏與公主長得像犁跪,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子歹袁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理坷衍,服務(wù)發(fā)現(xiàn),斷路器条舔,智...
    卡卡羅2017閱讀 134,652評(píng)論 18 139
  • 轉(zhuǎn)載: http://www.reibang.com/p/8b428e1d1564# JSON概覽 JSON(Ja...
    朝花夕拾不起來閱讀 2,645評(píng)論 1 37
  • 暑期枫耳,看書和看電視的時(shí)間Q貌似把握的不是很好。經(jīng)常一看就超時(shí)了孟抗。對(duì)此迁杨,我們開了家庭會(huì)議钻心,再次做了頭腦風(fēng)暴。最后一致...
    GraceQ媽閱讀 345評(píng)論 1 0
  • 我們一直在追求自我的實(shí)現(xiàn)铅协,自我實(shí)現(xiàn)應(yīng)該是大多數(shù)人的一個(gè)終極目標(biāo)捷沸。但是我們?cè)趯?shí)現(xiàn)的路上走了太多彎路。 人對(duì)自己的將來...
    關(guān)天行者閱讀 746評(píng)論 0 0
  • 在得到陸陸續(xù)續(xù)的聽了幾十本書狐史,書的種類很雜痒给,有些如果不是定閱了我是不會(huì)主動(dòng)去找來看的書,這些書都是些碎片時(shí)間聽...
    snailwww閱讀 1,523評(píng)論 0 2