├── .browserslistrc
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .npmignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── babel.config.js
├── dev
├── App.vue
├── assets
│ └── logo.png
├── descriptor.js
└── main.js
├── docs
├── .vuepress
│ ├── components
│ │ ├── array-demo.vue
│ │ ├── base-data-demo.vue
│ │ ├── code-demo.vue
│ │ ├── custom-component.vue
│ │ ├── custom-message.vue
│ │ ├── custom-validator.vue
│ │ ├── form-demo.vue
│ │ ├── form-operation.vue
│ │ ├── hashmap-demo.vue
│ │ ├── home-demo.vue
│ │ └── object-demo.vue
│ ├── config.js
│ ├── demos
│ │ └── cdn.html
│ ├── enhanceApp.js
│ └── public
│ │ ├── css
│ │ └── index.css
│ │ └── logo.png
├── README.md
├── api
│ ├── descriptors
│ │ └── README.md
│ └── dynamic-form
│ │ └── README.md
├── getting-started
│ └── README.md
├── guide
│ └── README.md
├── i18n
│ └── README.md
└── zh
│ ├── README.md
│ ├── api
│ ├── descriptors
│ │ └── README.md
│ └── dynamic-form
│ │ └── README.md
│ ├── getting-started
│ └── README.md
│ ├── guide
│ └── README.md
│ └── i18n
│ └── README.md
├── package.json
├── packages
├── dynamic-component
│ ├── component.vue
│ └── index.js
├── dynamic-form-item
│ ├── form-item.vue
│ └── index.js
├── dynamic-form
│ ├── form.vue
│ └── index.js
├── dynamic-input
│ ├── index.js
│ └── input.vue
├── i18n.js
├── index.js
└── utils.js
├── postcss.config.js
├── public
├── index.html
└── vue-dynamic-form-component.gif
├── types
└── index.d.ts
├── vetur
├── attributes.json
└── tags.json
├── vue.config.js
└── yarn.lock
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{js,jsx,ts,tsx,vue}]
2 | indent_style = space
3 | indent_size = 2
4 | trim_trailing_whitespace = true
5 | insert_final_newline = true
6 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /lib
3 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true
5 | },
6 | 'extends': [
7 | 'plugin:vue/essential',
8 | '@vue/standard'
9 | ],
10 | rules: {
11 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
13 | },
14 | parserOptions: {
15 | parser: 'babel-eslint'
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | dist
4 | lib
5 | docs/.vuepress/dist
6 |
7 | # local env files
8 | .env.local
9 | .env.*.local
10 |
11 | # Log files
12 | npm-debug.log*
13 | yarn-debug.log*
14 | yarn-error.log*
15 |
16 | # Editor directories and files
17 | .idea
18 | .vscode
19 | *.suo
20 | *.ntvs*
21 | *.njsproj
22 | *.sln
23 | *.sw?
24 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | docs
4 | dev
5 | node_modules
6 | packages
7 | public
8 |
9 | # local env files
10 | .env.local
11 | .env.*.local
12 |
13 | # Log files
14 | npm-debug.log*
15 | yarn-debug.log*
16 | yarn-error.log*
17 |
18 | # Editor directories and files
19 | .idea
20 | .vscode
21 | *.suo
22 | *.ntvs*
23 | *.njsproj
24 | *.sln
25 | *.sw?
26 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4 |
5 |
6 | ## [2.8.1](https://github.com/chenquincy/vue-dynamic-form-component/compare/v2.8.0...v2.8.1) (2020-10-20)
7 |
8 |
9 | ### Bug Fixes
10 |
11 | * **$dynamic-input:** can set float value with number type ([1b75918](https://github.com/chenquincy/vue-dynamic-form-component/commit/1b75918)), closes [#33](https://github.com/chenquincy/vue-dynamic-form-component/issues/33)
12 |
13 |
14 |
15 |
16 | # [2.8.0](https://github.com/chenquincy/vue-dynamic-form-component/compare/v2.7.0...v2.8.0) (2020-09-17)
17 |
18 |
19 | ### Features
20 |
21 | * support form disabled ([7e51ba4](https://github.com/chenquincy/vue-dynamic-form-component/commit/7e51ba4))
22 |
23 |
24 |
25 |
26 | # [2.7.0](https://github.com/chenquincy/vue-dynamic-form-component/compare/v2.6.0...v2.7.0) (2020-09-16)
27 |
28 |
29 | ### Features
30 |
31 | * support to custom component for complex type ([b4dc2c5](https://github.com/chenquincy/vue-dynamic-form-component/commit/b4dc2c5))
32 |
33 |
34 |
35 |
36 | # [2.6.0](https://github.com/chenquincy/vue-dynamic-form-component/compare/v2.5.0...v2.6.0) (2020-07-21)
37 |
38 |
39 | ### Bug Fixes
40 |
41 | * upgrade danger deps ([2cc882a](https://github.com/chenquincy/vue-dynamic-form-component/commit/2cc882a))
42 |
43 |
44 | ### Features
45 |
46 | * add vetur prompt ([7992313](https://github.com/chenquincy/vue-dynamic-form-component/commit/7992313))
47 |
48 |
49 |
50 |
51 | # [2.2.0](https://github.com/chenquincy/vue-dynamic-form-component/compare/v2.1.0...v2.2.0) (2019-09-01)
52 |
53 |
54 | ### Features
55 |
56 | * support autocomplete ([07c91da](https://github.com/chenquincy/vue-dynamic-form-component/commit/07c91da))
57 |
58 |
59 |
60 |
61 | ## [2.0.1](https://github.com/chenquincy/vue-dynamic-form-component/compare/v2.0.0...v2.0.1) (2019-08-11)
62 |
63 |
64 | ### Bug Fixes
65 |
66 | * fix language setting and docs import element-ui error. ([1522330](https://github.com/chenquincy/vue-dynamic-form-component/commit/1522330))
67 |
68 |
69 |
70 | # Change Log
71 |
72 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
73 |
74 | # [2.0.0](https://github.com/chenquincy/vue-dynamic-form-component/compare/v1.1.2...v2.0.0) (2019-08-02)
75 |
76 |
77 | ### Features
78 |
79 | * change vue, element-ui to externals. ([5c46661](https://github.com/chenquincy/vue-dynamic-form-component/commit/5c46661)), closes [#1](https://github.com/chenquincy/vue-dynamic-form-component/issues/1)
80 |
81 |
82 | ### BREAKING CHANGES
83 |
84 | * The default languages change to zh_CN from en_US;Should import vue and element-ui
85 | yourself.
86 |
87 |
88 |
89 | ## [1.1.2](https://github.com/chenquincy/vue-dynamic-form-component/compare/v1.1.1...v1.1.2) (2019-07-17)
90 |
91 |
92 | ### Bug Fixes
93 |
94 | * lodash version upgrade(security issue) ([8f1f31b](https://github.com/chenquincy/vue-dynamic-form-component/commit/8f1f31b))
95 |
96 |
97 |
98 | ## [1.1.1](https://github.com/chenquincy/vue-dynamic-form-component/compare/v1.1.0...v1.1.1) (2019-06-27)
99 |
100 |
101 | ### Bug Fixes
102 |
103 | * export component error. ([c95b17e](https://github.com/chenquincy/vue-dynamic-form-component/commit/c95b17e))
104 |
105 |
106 |
107 | # [1.1.0](https://github.com/chenquincy/vue-dynamic-form-component/compare/v1.0.3...v1.1.0) (2019-06-26)
108 |
109 |
110 | ### Features
111 |
112 | * add hidden prop and support custom languages. ([b3419ab](https://github.com/chenquincy/vue-dynamic-form-component/commit/b3419ab))
113 |
114 |
115 |
116 | ## [1.0.3](https://github.com/chenquincy/vue-dynamic-form-component/compare/v1.0.2...v1.0.3) (2019-06-21)
117 |
118 |
119 | ### Bug Fixes
120 |
121 | * sub dynamic-form-item should pass lang prop, delete button style improve. ([6fe39b6](https://github.com/chenquincy/vue-dynamic-form-component/commit/6fe39b6))
122 |
123 |
124 |
125 | ## [1.0.2](https://github.com/chenquincy/vue-dynamic-form-component/compare/v1.0.1...v1.0.2) (2019-06-21)
126 |
127 |
128 | ### Bug Fixes
129 |
130 | * label-width compute error ([74d63c6](https://github.com/chenquincy/vue-dynamic-form-component/commit/74d63c6))
131 |
132 |
133 |
134 | ## [1.0.1](https://github.com/chenquincy/vue-dynamic-form-component/compare/v1.0.0...v1.0.1) (2019-06-20)
135 |
136 |
137 | ### Bug Fixes
138 |
139 | * change name to vue-dynamic-form-component ([2ffea42](https://github.com/chenquincy/vue-dynamic-form-component/commit/2ffea42))
140 | * change package name ([8b9e15c](https://github.com/chenquincy/vue-dynamic-form-component/commit/8b9e15c))
141 | * parent form's label-width compute error. ([8d5b369](https://github.com/chenquincy/vue-dynamic-form-component/commit/8d5b369))
142 |
143 |
144 |
145 | # 1.0.0 (2019-06-19)
146 |
147 |
148 | ### Bug Fixes
149 |
150 | * child object init error ([93c9995](https://github.com/chenquincy/vue-dynamic-form-component/commit/93c9995))
151 | * package.json main error, change name to vue-dynamic-form2 ([f71b389](https://github.com/chenquincy/vue-dynamic-form-component/commit/f71b389))
152 |
153 |
154 | ### Features
155 |
156 | * finish dynamic-form develop. ([839a3c0](https://github.com/chenquincy/vue-dynamic-form-component/commit/839a3c0))
157 | * finish version 0.0.1 ([944e16a](https://github.com/chenquincy/vue-dynamic-form-component/commit/944e16a))
158 | * finish vue-dynamic-form's data and props init. ([19b9a5e](https://github.com/chenquincy/vue-dynamic-form-component/commit/19b9a5e))
159 | * finish vue-dynamic-input component. ([4ceb688](https://github.com/chenquincy/vue-dynamic-form-component/commit/4ceb688))
160 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 QuincyChen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Introduction
2 |
3 | **vue-dynamic-form-component** is a dynamic form component base on [element-ui](https://element.faas.ele.me/#/zh-CN) and [async-validator](https://github.com/yiminghe/async-validator). You just need to write **descriptors**(reference to [async-validator](https://github.com/yiminghe/async-validator)) of the data you want, **vue-dynamic-form-component** will generate the form automatically.
4 |
5 | ## Docs
6 |
7 | - [English Docs](https://vue-dynamic-form.quincychen.cn)
8 | - [中文文档](https://vue-dynamic-form.quincychen.cn/zh/)
9 |
10 | ## Usage Example
11 |
12 | 
13 |
14 | ``` vue
15 |
16 |
20 |
21 | reset
22 | validate
23 |
24 |
25 |
26 |
27 |
77 | ```
78 |
79 | ## Features
80 |
81 | - Generate form from **descriptors**
82 | - Support almost all data type
83 | - Support **multi-level form** for `Object `/ `Array` / `Hashmap`
84 | - Support data **validation**
85 | - **Multi-Languages** support
86 | - Support **custom component**
87 |
88 | ## Todo
89 |
90 | **vue-dynamic-form-component** can do more. There are a few things that it currently doesn't support but are planned:
91 |
92 | - [x] Custom component props
93 | - [x] Custom component event
94 | - [x] Custom component
95 | - [ ] Custom theme
96 | - [ ] Value change event
97 |
98 | ## Question
99 |
100 | Please submit your question in [Github Issue](https://github.com/chenquincy/vue-dynamic-form-component/issues) .
101 |
102 | ## License
103 |
104 | [MIT license](https://tldrlegal.com/license/mit-license)
105 |
106 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/app'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/dev/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 | Reset
12 | Validate
13 |
14 |
15 |
16 |
17 |
18 |
49 |
50 |
59 |
--------------------------------------------------------------------------------
/dev/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenquincy/vue-dynamic-form-component/8d061c21d7fb637a5117d3a65ee6cc438e348c48/dev/assets/logo.png
--------------------------------------------------------------------------------
/dev/descriptor.js:
--------------------------------------------------------------------------------
1 | export default {
2 | string: { type: 'string', required: true, disabled: true, placeholder: 'textarea placeholder', props: { autocomplete: 'on', type: 'textarea', rows: 4 } },
3 | url: { type: 'url', message: 'The url must be an url' },
4 | object: {
5 | type: 'object',
6 | label: 'object label',
7 | fields: {
8 | boolean: { type: 'boolean', required: true },
9 | string: { type: 'string', required: true, hidden: false },
10 | date: { type: 'date', required: true },
11 | url: { type: 'url', message: 'The url must be an url', props: { placeholder: 'please input the url' } }
12 | }
13 | },
14 | hashmap: {
15 | type: 'object',
16 | label: 'hashmap label',
17 | defaultField: {
18 | type: 'string',
19 | required: true
20 | }
21 | },
22 | array: {
23 | type: 'array',
24 | label: 'array label',
25 | defaultField: {
26 | type: 'object',
27 | fields: {
28 | string: { type: 'string', required: true },
29 | url: { type: 'url', message: 'The url must be an url', props: { placeholder: 'please input the url' } }
30 | }
31 | }
32 | },
33 | multiSelect: {
34 | type: 'array',
35 | label: 'array label',
36 | defaultField: {
37 | type: 'enum',
38 | multiple: true,
39 | enum: [0, 1, 2, 3],
40 | options: [
41 | { label: 'option-0', value: 0, disabled: true },
42 | { label: 'option-1', value: 1 },
43 | { label: 'option-2', value: 2 },
44 | { label: 'option-3', value: 3 }
45 | ]
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/dev/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import ElementUI from 'element-ui'
3 | import 'element-ui/lib/theme-chalk/index.css'
4 | import locale from 'element-ui/lib/locale/lang/en'
5 | import DynamicForm from '../packages/index'
6 |
7 | import App from './App.vue'
8 |
9 | Vue.config.productionTip = false
10 | Vue.use(ElementUI, { locale })
11 | Vue.use(DynamicForm)
12 |
13 | new Vue({
14 | render: h => h(App)
15 | }).$mount('#app')
16 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/array-demo.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/base-data-demo.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/code-demo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ lang === 'en_US' ? 'Click To Show/Hide Demo' : '点击显示/隐藏示例' }}
6 |
7 |
8 |
9 |
10 |
11 |
12 |
34 |
35 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/custom-component.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/custom-message.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/custom-validator.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/form-demo.vue:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 | clearValidate
13 | resetFields
14 | validate
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/form-operation.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 | clearValidate
9 | resetFields
10 | validate
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/hashmap-demo.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/home-demo.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 | Reset
10 | Validate
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/object-demo.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/docs/.vuepress/config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | head: [
3 | ['link', { rel: 'icon', href: '/logo.png' }]
4 | ],
5 | locales: {
6 | '/': {
7 | lang: 'en-US',
8 | title: 'vue-dynamic-form-component',
9 | description: 'Vue dynamic nested form component. Support nested Object/Hashmap/Array. Can custom component yourself.'
10 | },
11 | '/zh/': {
12 | lang: 'zh-CN',
13 | title: 'vue-dynamic-form-component',
14 | description: 'Vue动态嵌套表单组件,支持嵌套对象/Hashmap/数组, 可自定义表单组件'
15 | }
16 | },
17 | themeConfig: {
18 | sidebarDepth: 2,
19 | lastUpdated: 'Last Updated',
20 | locales: {
21 | '/': {
22 | selectText: 'Languages',
23 | label: 'English',
24 | sidebar: [
25 | { title: 'Guide', collapsable: false, children: ['/guide/', '/getting-started/', '/i18n/'] },
26 | { title: 'API', collapsable: false, children: ['/api/dynamic-form/', '/api/descriptors/'] }
27 | ]
28 | },
29 | '/zh/': {
30 | selectText: '语言',
31 | label: '简体中文',
32 | sidebar: [
33 | { title: '指南', collapsable: false, children: ['/zh/guide/', '/zh/getting-started/', '/zh/i18n/'] },
34 | { title: 'API', collapsable: false, children: ['/zh/api/dynamic-form/', '/zh/api/descriptors/'] }
35 | ]
36 | }
37 | },
38 | nav: [
39 | { text: 'GitHub', link: 'https://github.com/chenquincy/vue-dynamic-form-component' },
40 | { text: 'v1.x', link: 'https://vue-dynamic-form.v1.quincychen.cn' }
41 | ]
42 | },
43 | plugins: {
44 | 'sitemap': {
45 | hostname: 'https://vue-dynamic-form.quincychen.cn',
46 | exclude: ['/404.html']
47 | },
48 | '@vuepress/plugin-google-analytics': {
49 | ga: 'UA-145341224-1'
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/docs/.vuepress/demos/cdn.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
31 |
--------------------------------------------------------------------------------
/docs/.vuepress/enhanceApp.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import ElementUI from 'element-ui'
3 | import 'element-ui/lib/theme-chalk/index.css'
4 | import locale from 'element-ui/lib/locale/lang/en'
5 | import DynamicForm from '../../packages/index'
6 | import './public/css/index.css'
7 |
8 | export default ({
9 | Vue
10 | }) => {
11 | Vue.use(ElementUI, { locale })
12 | Vue.use(DynamicForm)
13 | }
14 |
--------------------------------------------------------------------------------
/docs/.vuepress/public/css/index.css:
--------------------------------------------------------------------------------
1 | .el-date-picker table {
2 | display: table;
3 | }
4 |
--------------------------------------------------------------------------------
/docs/.vuepress/public/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenquincy/vue-dynamic-form-component/8d061c21d7fb637a5117d3a65ee6cc438e348c48/docs/.vuepress/public/logo.png
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | home: true
3 | heroImage: /logo.png
4 | actionText: Getting Started →
5 | actionLink: /getting-started/
6 | meta:
7 | - name: keywords
8 | content: vue dynamic nested form component vue-dynamic-form vue-dynamic-form-component
9 | - name: google-site-verification
10 | content: -lX8u-MYYDkf5y6QhZWJqZoDxVkmAu004XwR3ynRwFg
11 | features:
12 | - title: Generate form by descriptors Or custom component
13 | details: Write only data's descriptor(extend from async-validate), then automatically generate form(use element-ui)
14 | - title: Support almost all data type with validation
15 | details: Support almost all data type and normal data validation(email, url, ... etc)
16 | - title: Support nested object/array
17 | details: Support nested object/array. Generate multi-level form, darken child form's background automatically
18 | footer: MIT Licensed | Copyright © QuincyChen
19 | ---
20 |
21 |
22 |
23 | ### Example
24 |
25 |
26 |
27 | <<< @/docs/.vuepress/components/home-demo.vue
28 |
29 |
--------------------------------------------------------------------------------
/docs/api/descriptors/README.md:
--------------------------------------------------------------------------------
1 | # descriptors
2 |
3 | **descriptors** is extended from [async-validator](https://github.com/yiminghe/async-validator). Just need to write **descriptors** follow the rules,**vue-dynamic-form-component** will generate the form component automatically(use [element-ui](https://element.faas.ele.me)).
4 |
5 | **descriptors** 's format: `{ : }`, the `descriptor` can be object or array.
6 |
7 |
8 |
9 | ## descriptor
10 |
11 | ::: tip Warm Prompt
12 | **descriptor** can be `object` or `array`, but the `fields`, `defaultFields`, `label`, `hidden`, `disabled`, `options`, `component` props should be brother props with `type`. In addition, there is only one object include `type` prop in array.
13 | :::
14 |
15 | ### type
16 |
17 | `string`, declare the type of data's field, include common data type.
18 |
19 | ::: warning 注意
20 |
21 | Note that [descriptor.component.name](/zh/api/descriptors/#props) has higher priority, the follow rules are invalid if `descriptor.component.name` is not null.
22 | :::
23 |
24 | | Value | Description | Component |
25 | | --------- | ------------------------------------------------------------ | ------------------- |
26 | | `string` | Must be a string | `el-input` |
27 | | `number` | Must be a number | `el-input` |
28 | | `boolean` | Must be a boolean | `el-switch` |
29 | | `regexp` | Must be an instance of `RegExp` or a string that does not generate an exception when creating a new `RegExp`. | `el-input` |
30 | | `integer` | Must be of type `number` and an integer. | `el-input` |
31 | | `float` | Must be of type `number` and a floating point number. | `el-input` |
32 | | `enum` | Value must exist in the `enum`. Can be used with [enum, options](/api/descriptors/#enum-options) | `el-select` |
33 | | `date` | Value must be valid as determined by `Date` | `el-date-picker` |
34 | | `url` | Must be of type `url` | `el-input` |
35 | | `hex` | Must be of type `hex` | `el-input` |
36 | | `email` | Must be of type `email` | `el-input` |
37 | | `object` | Must be of type `object` and not `Array.isArray`. Use with `fields` or `defaultField` | `dynamic-form-item` |
38 | | `array` | Must be an array as determined by `Array.isArray`. Use with `defaultField` | `dynamic-form-item` |
39 |
40 | ### label
41 |
42 | `string`, field's label in form, should be declared with `type` in the same object.
43 |
44 | ### hidden
45 |
46 | `boolean` , whether hidden the input component of value, should be declared with `type` in the same object. Note that the hidden value still will be validated while validating.
47 |
48 | ### disabled
49 |
50 | `boolean`, whether input component disabled, default `false`.
51 |
52 | ### required
53 |
54 | `boolean`, is field required, without or `false` means the field is not required.
55 |
56 | ### pattern
57 |
58 | `Regexp`, the field's value must match to pass validation.
59 |
60 | ### min | max
61 |
62 | `number`, can be used for `string`, `array`, `number`
63 |
64 | For `string` and `array`, field's length should in `[min, max]`. For `number`, field's value should in `[min, max]`.
65 |
66 | ### len
67 |
68 | `number`, can be used for `string`, `array`, `number`
69 |
70 | For `string` and `array`, field's length should equal to `len`. For `number`, field's value should equal to `len`.
71 |
72 | > If the `len` property is combined with the `min` and `max` range properties, `len` takes precedence.
73 |
74 | ### enum, options
75 |
76 | `array`, only can be used while `type === 'enum'`, here is the format:
77 |
78 | ```js
79 | {
80 | type: 'enum',
81 | enum: [0, 1, 2],
82 | options: [
83 | { label: 'female', value: 0 },
84 | { label: 'male', value: 1 },
85 | { label: 'secret', value: 2, disabled: true }
86 | ]
87 | }
88 | ```
89 |
90 | `options` is optional, `label === value` without `options`
91 |
92 | ### whitespace
93 |
94 | `boolean`, only can be used while `type === 'string'`. Validate error if value only contain whitespace.
95 |
96 | ### message
97 |
98 | `string`, cover the default error message, one validate rule can have one message.
99 |
100 | ```js
101 | const descriptors = {
102 | name: [
103 | { type: 'string', required: true, message: 'username is required' },
104 | { min: 3, max 20, message: 'username length must between 3 to 20' },
105 | { whitespace: true, message: 'username can not be whitespace' }
106 | ]
107 | }
108 | ```
109 |
110 | ### fields
111 |
112 | `object`, only can be used while `type === 'object'`. You can use it if the child fields have different value format. Actually, it is the `descriptors` of field's value, your use it to get **nested object**.
113 |
114 | ```js
115 | const descriptors = {
116 | company: {
117 | type: 'object',
118 | fields: {
119 | name: { type: 'string', required: true },
120 | address: {
121 | type: 'object',
122 | fields: {
123 | country: { type: 'string', required: true },
124 | province: { type: 'string', required: true }
125 | }
126 | }
127 | }
128 | }
129 | }
130 | ```
131 |
132 | The above `descriptors` get the data with this structure:
133 |
134 | ```js
135 | {
136 | company: {
137 | name: String,
138 | address: {
139 | country: String,
140 | province: String
141 | }
142 | }
143 | }
144 | ```
145 |
146 | ### defaultField
147 |
148 | `object | array`, priority to `fields`, only can be used while `type === 'object' | 'array'`. You can use it if the child fields have same value format. Actually, it is the `descriptor` of field, you can use it to get complex data structures like **Hashmap** or **multidimensional arrays**.
149 |
150 | ```js
151 | const descriptors = {
152 | dict: {
153 | type: 'object',
154 | defaultField: { type: 'string', required: true }
155 | },
156 | array2d: {
157 | type: 'array',
158 | defaultField: {
159 | type: 'array',
160 | defaultField: { type: 'string', required: true }
161 | }
162 | }
163 | }
164 | ```
165 |
166 | The above `descriptors` get the data with this structure:
167 |
168 | ```js
169 | {
170 | dict: {
171 | : String
172 | },
173 | array2d: [
174 | [String]
175 | ]
176 | }
177 | ```
178 |
179 | ### validator
180 |
181 | `Function`, custom the validate function with format: `validator(rule: Object, value, callback: Function)`
182 |
183 | - `rule`
184 |
185 | the validate rule of the field
186 |
187 | - `value`
188 |
189 | the value of the field
190 |
191 | - `callback`
192 |
193 | callback function of validation. `callback(new Error())` means validate error, `message` is the error message. `callback()` means validate success.
194 |
195 | ```js
196 | const descriptors = {
197 | name: [
198 | { type: 'string', required: true },
199 | {
200 | validator: function (rule, value, callback) {
201 | if (value.length < 5) {
202 | return callback(new Error('name should logger than 5'))
203 | }
204 | if (value.indexOf('/%$') !== -1) {
205 | return callback(new Error('name can not include /%$'))
206 | }
207 | return callback()
208 | }
209 | }
210 | ]
211 | }
212 | ```
213 |
214 | ### component
215 |
216 | Provided for user to custom the component easily, it can custom the component's content, props and events.
217 |
218 | ``` js
219 | // component demo
220 | {
221 | name: 'el-button',
222 | props: {
223 | type: 'primary',
224 | size: 'small'
225 | },
226 | events: {
227 | click () {
228 | console.log('button click')
229 | }
230 | }
231 | }
232 | ```
233 |
234 | #### name
235 |
236 | `string` type, custom to use which element or component.
237 |
238 | #### props
239 |
240 | `object` type, it will be the value of input component's `v-bind` prop(input component refer to [descriptor.type](/api/descriptors/#type)). You can custom the component props with this option, there are some common props like: `placeholder`, `disabled`, ... , etc. Other props of component refer to [element-ui](https://element.faas.ele.me/#/en-US/component/installation). Note that it will be the value of the custom component's `v-bind` prop, if `component.name` is not null.
241 |
242 | #### events
243 |
244 | `object` type, it will be the value of input component's `v-on` prop(input component refer to [descriptor.type](/api/descriptors/#type)). You can custom the component props with this option, there are some common prop like: `placeholder`, `disabled`, ... , etc. Other props of component refer to [element-ui](https://element.faas.ele.me/#/en-US/component/installation). Note that it will be the value of the custom component's `v-on` prop, if `component.name` is not null.
245 |
246 | #### children
247 |
248 | `children` is used to custom the content of component. It has two types:
249 |
250 | - `string` : the content is plain text. It will be inserted with `span` element
251 | - `array[component | string]` : the content has more than one element, the array item has two types:
252 | - `component` : same structure with [component](/api/descriptors/#component)
253 | - `string` : the item is plain text. It will be inserted with `span` element
--------------------------------------------------------------------------------
/docs/api/dynamic-form/README.md:
--------------------------------------------------------------------------------
1 | # dynamic-form
2 |
3 | ## Props
4 |
5 | | prop | description | type | option values | default | required |
6 | | --------------- | ------------------------------------------------------------ | ------- | ------------------- | ------- | -------- |
7 | | value | form data | object | | | yes |
8 | | lang | language | string | en_US,zh_CN | zh_CN | |
9 | | languages | custom language pack | object | | | |
10 | | descriptors | descriptors of form data, refer to [descriptor](/zh/api/descriptors/) | object | | | yes |
11 | | size | size of form component | string | medium,small,mini | small | |
12 | | disabled | whether form is disabled | boolean | | false | |
13 | | backgroundColor | root form background color | string | Hex color or 'none' | none | |
14 | | fontSize | font size of form | number | | 14 | |
15 | | bgColorOffset | form background color offset | number | | 8 | |
16 | | showOuterError | whether show parent component's error | boolean | | true | |
17 |
18 | `languages` format:
19 |
20 | ```js
21 | // refer to lang prop
22 | {
23 | : {
24 | addKeyPlaceholder: 'Input the key you want to add',
25 | addKeyButtonText: 'Add Key',
26 | addArrayItemButtonText: 'Add Item'
27 | }
28 | }
29 | ```
30 |
31 |
32 |
33 | ## Slots
34 |
35 | | slot name | description |
36 | | ---------- | ------------------------------------------------------------ |
37 | | operations | operation slot for form, use to put submit/reset button generally |
38 |
39 | ## Methods
40 |
41 | | method | description | params |
42 | | ------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
43 | | validate | validate the form. Takes a optional callback function as a param. Callback function will be executed with one param(validate result) while having the callback param. Return a promise(resolve validate result) without callback param. | Function(callback: (valid) => {}):void \| Function():Promise(Boolean) |
44 | | resetFields | reset form and remove validation result | () => {} |
45 | | clearValidate | clear validation message of form | () => {} |
46 |
47 | ## Example
48 |
49 |
50 |
51 | <<< @/docs/.vuepress/components/form-demo.vue
52 |
53 |
--------------------------------------------------------------------------------
/docs/getting-started/README.md:
--------------------------------------------------------------------------------
1 | # Getting Started
2 |
3 | ::: tip Warm Prompt
4 | vue-dynamic-form-component should use with [Vue](https://vuejs.org/) and [element-ui](https://element.faas.ele.me), please install them first.
5 | :::
6 |
7 | ## Installation
8 |
9 | ### CDN
10 |
11 | Get the latest version from [unpkg.com/vue-dynamic-form-component](https://unpkg.com/vue-dynamic-form-component/), and import the javascript file in your page.
12 |
13 | <<<@/docs/.vuepress/demos/cdn.html
14 |
15 |
16 |
17 | ### NPM
18 |
19 | Installing with npm is recommended and it works seamlessly with [webpack](https://webpack.js.org/).
20 |
21 | ``` bash
22 | # yarn
23 | yarn add vue-dynamic-form-component
24 | # or npm
25 | npm install vue-dynamic-form-component
26 | ```
27 |
28 |
29 |
30 | ## Registration
31 |
32 | ### Global Registered
33 |
34 | ``` js
35 | import Vue from 'Vue'
36 | import ElementUI from 'element-ui'
37 | import 'element-ui/lib/theme-chalk/index.css'
38 | Vue.use(ElementUI)
39 |
40 | import DynamicForm from 'vue-dynamic-form-component'
41 | Vue.use(DynamicForm)
42 | ```
43 |
44 | ### Registered in Component
45 |
46 | ::: tip Warm Prompt
47 | Don't forget to register the [element-ui](https://element.faas.ele.me) first.
48 | :::
49 |
50 | ``` vue
51 |
59 | ```
60 |
61 | ## Usage
62 |
63 | ### Simple Data Type
64 |
65 | The component support common data type:`string`, `number`, `boolean`, `integer`, `float`, `enum`, `date`, `url`, `hex`, `email` and so on, more type reference to [descriptor.type](/api/descriptors/#type)
66 |
67 |
68 |
69 | <<<@/docs/.vuepress/components/base-data-demo.vue
70 |
71 | ### Object
72 |
73 | To generate **Object**, use `type: 'object'` with `fields`
74 |
75 |
76 |
77 | <<<@/docs/.vuepress/components/object-demo.vue
78 |
79 | ### Hashmap
80 |
81 | To generate **Hashmap**, use `type: 'object'` with `defaultField`
82 |
83 |
84 |
85 | <<<@/docs/.vuepress/components/hashmap-demo.vue
86 |
87 | ### Array
88 |
89 | To generate **Array**, use `type: 'array'` with `defaultField`. If the array items are enumerable, you can use `type: 'enum'` in `defaultField` with `multiple: true`. It will generate a multi-select component.
90 |
91 |
92 |
93 | <<<@/docs/.vuepress/components/array-demo.vue
94 |
95 | ### Custom Validation
96 |
97 | Generally, you don't need to write extra code for field's validation. **vue-dynamic-form-component** provides default validate rule and message base on `type`。
98 |
99 | If you need to custom the validate rule or message, you can use the following methods
100 |
101 | #### Custom Validate Message
102 |
103 | You can cover the default validate message by adding the `message` prop. You can add multi rule for one field by using `Array`.
104 |
105 | ::: warning Warning
106 | Special prop `label`, `fields`, `defaultField` , ...etc should be used with `type` in one rule. Reference to [descriptor.type](/api/descriptors/#descriptor)
107 | :::
108 |
109 |
110 |
111 | <<<@/docs/.vuepress/components/custom-message.vue
112 |
113 | #### Custom Validator
114 |
115 | **vue-dynamic-form-component** provides many configurations to meet most of validate rules. Here are some common configurations, more configurations reference to [descriptor](/api/descriptors/#descriptor).
116 |
117 | | Prop | Type | Description |
118 | | --------- | ------------------------------- | ------------------------------------------------------------ |
119 | | required | Boolean | whether the prop value is required |
120 | | pattern | RegExp | regexp to match prop value |
121 | | len | Number | validate `length` of `string` or `array` |
122 | | validator | Function(rule, value, callback) | Custom validate function, `callback(Error)` mean validate error, `callback()` mean validate success |
123 |
124 |
125 |
126 | <<<@/docs/.vuepress/components/custom-validator.vue
127 |
128 | ### Custom Component
129 |
130 | ::: tip Warm Prompt
131 |
132 | To custom component, you should ensure `version >= 2.5.0`
133 | :::
134 |
135 | **vue-dynamic-form-component** has components for common data type inside, so you don't need to custom the component generally. But sometimes, we need to custom the component, such as upload a file. To meet these scenes, I provide a way to custom the component. Usage like this:
136 |
137 |
138 |
139 | <<<@/docs/.vuepress/components/custom-component.vue
140 |
141 | The component was writed by used `v-model` , so you can use the custom component directly after changing the `component.name`. The component structure in descriptors is:
142 |
143 | ``` js
144 | component: {
145 | name: 'el-radio-group', // component's name
146 | props: {}, // component's props
147 | events: {}, // component's events
148 | children: [], // component or string(plain text dom)
149 | }
150 | ```
151 |
152 | #### Component without v-model
153 |
154 | If you want to use component like `el-image` that without v-model, you need to write a component yourself.
155 |
156 | First, write the custom component:
157 |
158 | ``` vue
159 |
160 |
161 |
162 |
163 |
164 |
165 |
185 | ```
186 |
187 | Then, register it global:
188 |
189 | ``` js
190 | import MyImage from './MyImage'
191 | Vue.component(MyImage.name, MyImage)
192 | ```
193 |
194 | Finally, you can use the component like previous step.
195 |
196 | Also, you can add more feature to you custom component, such as set to default value when the image loaded error:
197 |
198 | ``` vue
199 |
200 |
201 |
202 |
203 |
204 |
205 |
230 | ```
231 |
232 |
233 |
234 | ### Form Operations
235 |
236 | **vue-dynamic-form-component** provides some common methods to operate form, you can use them with `operations` slot.
237 |
238 | ::: tip Warm Prompt
239 | The document import the `el-button` component for convenience, you should import by yourself, if you need it in actual use. You can refer the specific parameters of form methods to [Component Methods](/api/dynamic-form/#methods).
240 | :::
241 |
242 |
243 |
244 | <<<@/docs/.vuepress/components/form-operation.vue{6,7,8,9,10}
245 |
246 |
--------------------------------------------------------------------------------
/docs/guide/README.md:
--------------------------------------------------------------------------------
1 | # Introduction
2 |
3 | **vue-dynamic-form-component** is a dynamic form component base on [element-ui](https://element.faas.ele.me/#/zh-CN) and [async-validator](https://github.com/yiminghe/async-validator) , support nested Object/Hashmap/Array. You just need to write **descriptors**(reference to [async-validator](https://github.com/yiminghe/async-validator)) of the data you want, **vue-dynamic-form-component** will generate the form automatically.
4 |
5 | ## Features
6 |
7 | - Generate form from **descriptors**
8 | - Support almost all data type
9 | - Support **nested form** for `Object `/ `Array` / `Hashmap`
10 | - Support data **validation**
11 | - **Multi-Languages** support
12 | - Support **custom component**
13 |
14 | ## Question
15 |
16 | Please submit your question in [Github Issue](https://github.com/chenquincy/vue-dynamic-form-component/issues) .
17 |
18 | ## License
19 |
20 | [MIT license](https://tldrlegal.com/license/mit-license)
21 |
22 |
--------------------------------------------------------------------------------
/docs/i18n/README.md:
--------------------------------------------------------------------------------
1 | ## Internationalization
2 |
3 | The default language of component is Chinese. If you want to use the another language, you need to do some configurations.
4 |
5 | ## element-ui setting
6 |
7 | Firstly, we should set the i18n configurations of `element-ui`, because vue-dynamic-form-component is based on `element-ui`.
8 |
9 | ``` js
10 | import Vue from 'vue'
11 | import ElementUI from 'element-ui'
12 | import locale from 'element-ui/lib/locale/lang/en'
13 |
14 | Vue.use(ElementUI, { locale })
15 | ```
16 |
17 | You can see the more configuration way here: [element-ui multi-languages setting](https://element.faas.ele.me/#/zh-CN/component/i18n)
18 |
19 | ## component setting
20 |
21 | The component is designed with chinese and english languages inside, you can toggle language by `lang` prop.
22 |
23 | ``` vue
24 |
25 |
29 |
30 |
31 | ```
32 |
33 | prop-value map is:
34 |
35 | | Language | Value |
36 | | -------- | ----- |
37 | | Chinese | zh_CN |
38 | | English | en_US |
39 |
40 | ### Custom language packages
41 |
42 | You can use `languages` prop to custom the languages by yourself, this is the `languages` format:
43 |
44 | ``` js
45 | {
46 | 'en_US': {
47 | addKeyPlaceholder: 'Input the key you want to add',
48 | addKeyButtonText: 'Add Key',
49 | addArrayItemButtonText: 'Add Item'
50 | },
51 | 'zh_CN': {
52 | ...
53 | }
54 | }
55 | ```
56 |
57 | ``` html
58 |
59 |
64 |
65 |
66 | ```
67 |
68 |
--------------------------------------------------------------------------------
/docs/zh/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | home: true
3 | heroImage: /logo.png
4 | actionText: 快速开始 →
5 | actionLink: /zh/getting-started/
6 | meta:
7 | - name: keywords
8 | content: vue 动态 嵌套 表单 多级 组件 vue-dynamic-form vue-dynamic-form-component
9 | features:
10 | - title: 使用descriptors生成表单或自定义组件
11 | details: 只需要提供目标数据的descriptor(基于async-validator扩展),就可以自动生成对应的表单元素(基于element-ui)
12 | - title: 支持绝大部分数据类型及其校验
13 | details: 支持绝大部分数据类型、常见类型校验(如:email、url等)
14 | - title: 支持多级数据对象
15 | details: 支持多级对象、数组,自动生成多级嵌套表单,子表单背景自定义加深
16 | footer: MIT Licensed | Copyright © QuincyChen
17 | ---
18 |
19 |
20 |
21 | ### 示例
22 |
23 |
24 |
25 | <<< @/docs/.vuepress/components/home-demo.vue
26 |
27 |
28 |
--------------------------------------------------------------------------------
/docs/zh/api/descriptors/README.md:
--------------------------------------------------------------------------------
1 | # descriptors
2 |
3 | **descriptors** 基于 [async-validator](https://github.com/yiminghe/async-validator) 扩展。只需要按照规则编写 **descriptors**,**vue-dynamic-form-component** 就会自动生成对应的表单元素(表单组件基于 [element-ui](https://element.faas.ele.me))。
4 |
5 | **descriptors** 的格式为:`{ : }`,其中,**descriptor** 可以是对象或者数组。
6 |
7 | ## descriptor
8 |
9 | ::: warning 注意
10 | **descriptor** 可以是对象或者数组,但是,当 **descriptor** 为数组时,与数据类型定义有关的属性( `fields`、`defaultFields`)和扩展属性(`label`、`hidden`、`disabled`、`options`、`component`) 需和 `type` 属性在同一对象中,并且数组中有且仅有一个包含 `type` 属性的对象。
11 | :::
12 |
13 | ### type
14 |
15 | `string` 类型,表示字段类型,包含常见的数据类型
16 |
17 | ::: warning 注意
18 | [descriptor.component.name](/zh/api/descriptors/#props) 优先级更高,当 `descriptor.component.name` 不为空时,以下规则不生效
19 | :::
20 |
21 | | 值 | 说明 | 对应组件 |
22 | | --------- | ------------------------------------------------------------ | ------------------- |
23 | | `string` | 字符串类型 | `el-input` |
24 | | `number` | `number`类型,自动添加 `.number` 修饰符 | `el-input` |
25 | | `boolean` | 布尔类型 | `el-switch` |
26 | | `regexp` | 正则表达式,必须是可以正确转化为 `RegExp` 实例的字符串 | `el-input` |
27 | | `integer` | `number` 类型的整数,自动添加 `.number` 修饰符 | `el-input` |
28 | | `float` | `number` 类型的浮点数,自动添加 `.number` 修饰符 | `el-input` |
29 | | `enum` | 枚举类型,需要和 [enum, options](/zh/api/descriptors/#enum-options) 属性配合使用,值必须是 `enum` 数组中的一个 | `el-select` |
30 | | `date` | 必须是合法的 `Date` 对象 | `el-date-picker` |
31 | | `url` | 符合链接格式的字符串 | `el-input` |
32 | | `hex` | 符合哈希格式的字符串 | `el-input` |
33 | | `email` | 符合邮件格式的字符串 | `el-input` |
34 | | `object` | `object` 类型,配合 `fields` 和 `defaultField` 使用 | `dynamic-form-item` |
35 | | `array` | `array` 类型,配合 `defaultField` 使用 | `dynamic-form-item` |
36 |
37 | ### label
38 |
39 | `string` 类型,表单中对应字段的label值,需和 `type` 在同一个对象中
40 |
41 | ### hidden
42 |
43 | `boolean` 类型,是否隐藏对应的输入组件,需和 `type` 在同一个对象中。需要注意的是,触发校验时,被隐藏的组件值依然会进行校验。
44 |
45 | ### disabled
46 |
47 | `boolean` 类型,输入组件是否不可编辑,默认为 `false`
48 |
49 | ### required
50 |
51 | `boolean` 类型,表示字段值是否为必须值,不填表示非必须
52 |
53 | ### pattern
54 |
55 | `Regexp` 类型,字段值必须符合该正则表达式
56 |
57 | ### min | max
58 |
59 | `number` 类型,适用于 `string`, `array`, `number` 类型
60 |
61 | 对于 `string` 或 `array` ,字段值的 `length` 必须介于 `min` 和 `max` 之间,对于 `number` 类型,值必须介于 `min` 和 `max` 之间
62 |
63 | ### len
64 |
65 | 精准匹配字段值的长度或大小,规则类似 `min | max`,`len` 优先级高于 `min | max`
66 |
67 | ### enum, options
68 |
69 | `array`类型,仅当 `type` 为 `enum` 时有效,用于列举字段值的所有选项,格式:
70 |
71 | ``` js
72 | {
73 | type: 'enum',
74 | enum: [0, 1, 2],
75 | options: [
76 | { label: 'female', value: 0 },
77 | { label: 'male', value: 1 },
78 | { label: 'secret', value: 2, disabled: true }
79 | ]
80 | }
81 | ```
82 |
83 | 当没有 `options` 时,`label === value`
84 |
85 | ### whitespace
86 |
87 | `boolean` 类型,仅适用于 `type === 'string'`,判断字段值是否为空(只包含空格的值也视为空)
88 |
89 | ### message
90 |
91 | `string` 类型,用于覆盖默认的错误提示信息,一个验证规则对应一条错误提示。
92 |
93 | ``` js
94 | const descriptors = {
95 | name: [
96 | { type: 'string', required: true, message: 'username is required' },
97 | { min: 3, max 20, message: 'username length must between 3 to 20' },
98 | { whitespace: true, message: 'username can not be whitespace' }
99 | ]
100 | }
101 | ```
102 |
103 | ### fields
104 |
105 | `object` 类型,只在 `type === 'object'` 时有效,当子字段值是不同格式时使用。事实上它就是字段值的 `descriptors`,你可以使用它来获取 **嵌套对象**。
106 |
107 | ``` js
108 | const descriptors = {
109 | company: {
110 | type: 'object',
111 | fields: {
112 | name: { type: 'string', required: true },
113 | address: {
114 | type: 'object',
115 | fields: {
116 | country: { type: 'string', required: true },
117 | province: { type: 'string', required: true }
118 | }
119 | }
120 | }
121 | }
122 | }
123 | ```
124 |
125 | 以上 `descriptors` 获取的数据格式为
126 |
127 | ``` js
128 | {
129 | company: {
130 | name: String,
131 | address: {
132 | country: String,
133 | province: String
134 | }
135 | }
136 | }
137 | ```
138 |
139 | ### defaultField
140 |
141 | `object | array` 类型,优先级高于 `fields`,只在 `type === 'object' | 'array'` 时有效,当子字段值是相同格式时使用。事实上它就是字段值的 `descriptor`,你可以使用它来获取 **Hashmap** 或 **多维数组** 等复杂类型。
142 |
143 | ``` js
144 | const descriptors = {
145 | dict: {
146 | type: 'object',
147 | defaultField: { type: 'string', required: true }
148 | },
149 | array2d: {
150 | type: 'array',
151 | defaultField: {
152 | type: 'array',
153 | defaultField: { type: 'string', required: true }
154 | }
155 | }
156 | }
157 | ```
158 |
159 | 以上 `descriptor` 获取的数据格式为
160 |
161 | ``` js
162 | {
163 | dict: {
164 | : String
165 | },
166 | array2d: [
167 | [String]
168 | ]
169 | }
170 | ```
171 |
172 | ### validator
173 |
174 | `Function` 类型,自定义校验函数,可以通过它来自定义校验规则,格式为:`validator(rule: Object, value, callback: Function)`
175 |
176 | * `rule`
177 |
178 | 当前校验的规则对象
179 |
180 | * `value`
181 |
182 | 对应字段的当前值
183 |
184 | * `callback`
185 |
186 | 校验回调函数,`callback(new Error())` 时表示校验不通过,`message`为显示的错误提示,`callback()` 表示校验通过
187 |
188 | ``` js
189 | const descriptors = {
190 | name: [
191 | { type: 'string', required: true },
192 | {
193 | validator: function (rule, value, callback) {
194 | if (value.length < 5) {
195 | return callback(new Error('name should logger than 5'))
196 | }
197 | if (value.indexOf('/%$') !== -1) {
198 | return callback(new Error('name can not include /%$'))
199 | }
200 | return callback()
201 | }
202 | }
203 | ]
204 | }
205 | ```
206 |
207 | ### component
208 |
209 | 为了方便使用者自定义组件提供的选项,可以自定义组件内容、属性和事件。
210 |
211 | ``` js
212 | // component 示例
213 | {
214 | name: 'el-button',
215 | props: {
216 | type: 'primary',
217 | size: 'small'
218 | },
219 | events: {
220 | click () {
221 | console.log('button click')
222 | }
223 | }
224 | }
225 | ```
226 |
227 | #### name
228 |
229 | `string` 类型,自定义组件名或元素名
230 |
231 | #### props
232 |
233 | `object` 类型,当 `component.name` 为空时,通过 `v-bind` 绑定到对应的组件(对应组件查阅 [descriptor.type](/zh/api/descriptors/#type)),可以通过该选项进行属性自定义,常见的属性有:`placeholder`、`disabled` 等,其他对应组件属性请查阅 [element-ui](https://element.faas.ele.me/#/zh-CN/component/installation) 对应组件文档;当 `component.name` 不为空时,通过 `v-bind` 绑定到声明的组件上。
234 |
235 | #### events
236 |
237 | `object` 类型,当 `component.name` 为空时,通过 `v-on` 绑定到对应的组件(对应组件查阅 [descriptor.type](/zh/api/descriptors/#type)),可以通过该选项进行事件自定义,例如:`click`、`focus` 等,其他对应组件事件请查阅 [element-ui](https://element.faas.ele.me/#/zh-CN/component/installation) 对应组件文档;当 `component.name` 不为空时,通过 `v-on` 绑定到声明的组件上。
238 |
239 | #### children
240 |
241 | `children` 用于自定义组件内容,它有两种类型:
242 |
243 | - `string` :表示内容为纯文本,使用 `span` 标签插入
244 | - `array[component | string]` : 表示组件内容有多个元素,数组元素有两种类型:
245 | - `component` : 结构和 [component](/zh/api/descriptors/#component) 相同
246 | - `string` : 表示纯文本元素,使用 `span` 标签插入
--------------------------------------------------------------------------------
/docs/zh/api/dynamic-form/README.md:
--------------------------------------------------------------------------------
1 | # dynamic-form
2 |
3 | ## 属性
4 |
5 | | 参数 | 说明 | 类型 | 可选值 | 默认值 | 必传 |
6 | | --------------- | ------------------------------------------------------------ | ------- | ----------------- | ------ | ---- |
7 | | value | 表单数据对象 | object | | | 是 |
8 | | lang | 显示语言 | string | en_US,zh_CN | zh_CN | |
9 | | languages | 自定义语言包 | object | | | |
10 | | descriptors | 表单数据对象的描述器,详见 [descriptor](/zh/api/descriptors/) | object | | | 是 |
11 | | size | 表单组件元素的大小 | string | medium,small,mini | small | |
12 | | disabled | 表单是否不可编辑 | boolean | | false | |
13 | | backgroundColor | 表单最外层背景 | string | 如:#FFFFFF | none | |
14 | | fontSize | 表单字体大小 | number | | 14 | |
15 | | bgColorOffset | 不同层级表单的背景色偏移量 | number | | 8 | |
16 | | showOuterError | 是否显示父组件的错误信息 | boolean | | true | |
17 |
18 | `languages` 格式:
19 |
20 | ``` js
21 | // 与 lang 属性对应
22 | {
23 | : {
24 | addKeyPlaceholder: 'Input the key you want to add',
25 | addKeyButtonText: 'Add Key',
26 | addArrayItemButtonText: 'Add Item'
27 | }
28 | }
29 | ```
30 |
31 |
32 |
33 | ## 插槽
34 |
35 | | 插槽名 | 说明 |
36 | | ---------- | ------------------------------------------ |
37 | | operations | 表单操作区插槽,一般用于放置提交、重置按钮 |
38 |
39 | ## 方法
40 |
41 | | 方法 | 说明 | 参数 |
42 | | ------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
43 | | validate | 触发表单的校验函数,有一个可选的callback函数。当传入callback函数时,回调函数会在校验结束后被调用;若不传参,则返回一个Promise,结果为表示校验是否通过的布尔值 | Function(callback: (valid) => {}):void \| Function():Promise(Boolean) |
44 | | resetFields | 重置表单,将所有字段重置为初始值并移除校验结果 | () => {} |
45 | | clearValidate | 移除校验结果 | () => {} |
46 |
47 | ## 示例
48 |
49 |
50 |
51 | <<< @/docs/.vuepress/components/form-demo.vue
52 |
53 |
--------------------------------------------------------------------------------
/docs/zh/getting-started/README.md:
--------------------------------------------------------------------------------
1 | # 快速上手
2 |
3 | ::: tip 温馨提示
4 | vue-dynamic-form-component 依赖于 [Vue](https://vuejs.org/) 和 [element-ui](https://element.faas.ele.me),请提前安装
5 | :::
6 |
7 | ## 安装
8 |
9 | ### CDN
10 |
11 | 目前可以通过 [unpkg.com/vue-dynamic-form-component](https://unpkg.com/vue-dynamic-form-component/) 获取最新版本的资源,使用示例:
12 |
13 | <<<@/docs/.vuepress/demos/cdn.html
14 |
15 |
16 |
17 | ### NPM
18 |
19 | 推荐使用 npm 的方式安装,它能更好地和 [webpack](https://webpack.js.org/) 打包工具配合使用。
20 |
21 | ``` bash
22 | # yarn
23 | yarn add vue-dynamic-form-component
24 | # or npm
25 | npm install vue-dynamic-form-component
26 | ```
27 |
28 |
29 |
30 | ## 注册
31 |
32 | ### 全局注册
33 |
34 | ``` js
35 | import Vue from 'Vue'
36 | import ElementUI from 'element-ui'
37 | import 'element-ui/lib/theme-chalk/index.css'
38 | Vue.use(ElementUI)
39 |
40 | import DynamicForm from 'vue-dynamic-form-component'
41 | Vue.use(DynamicForm)
42 | ```
43 |
44 | ### 组件内注册
45 |
46 | ::: tip 温馨提示
47 | 不要忘记提前注册 [element-ui](https://element.faas.ele.me)
48 | :::
49 |
50 | ``` vue
51 |
59 | ```
60 |
61 | ## 使用
62 |
63 | ### 简单类型
64 |
65 | 组件支持常见的输入类型:`string`, `number`, `boolean`, `integer`, `float`, `enum`, `date`, `url`, `email` 等等,更多类型请查阅 [descriptor.type](/zh/api/descriptors/#type)
66 |
67 |
68 |
69 | <<<@/docs/.vuepress/components/base-data-demo.vue
70 |
71 | ### 对象
72 |
73 | `type: 'object'` 与 `fields` 配合使用即可生成嵌套对象
74 |
75 |
76 |
77 | <<<@/docs/.vuepress/components/object-demo.vue
78 |
79 | ### HashMap
80 |
81 | `type: 'object'` 与 `defaultField` 配合使用即可生成 **Hashmap**
82 |
83 |
84 |
85 | <<<@/docs/.vuepress/components/hashmap-demo.vue
86 |
87 | ### 数组
88 |
89 | `type: 'array'` 与 `defaultField` 配合使用可以生成对应数组,当数组元素是可枚举类型时,推荐在 `defaultField` 中使用 `enum` 类型并设置 `multiple: true`,组件将会为这个数组生成一个多选下拉框。
90 |
91 |
92 |
93 | <<<@/docs/.vuepress/components/array-demo.vue
94 |
95 | ### 自定义校验
96 |
97 | 一般情况下,在你声明了 `type` 后,你不需要对字段编写额外的校验代码,**vue-dynamic-form-component** 自带了默认的校验规则及校验信息。
98 |
99 | 如果你需要自定义校验规则或校验信息,可以采用以下方式
100 |
101 | #### 自定义校验信息
102 |
103 | 给对应规则添加 `message` 字段即可覆盖原校验信息,可以使用数组形式给一个属性添加多条规则
104 |
105 | ::: warning 注意
106 | 特殊属性 `label`, `fields`, `defaultField` 等只能和 `type` 属性在同一规则中,具体查阅 [descriptor.type](/zh/api/descriptors/#type)
107 | :::
108 |
109 |
110 |
111 | <<<@/docs/.vuepress/components/custom-message.vue
112 |
113 | #### 自定义规则
114 |
115 | **vue-dynamic-form-component** 提供了很多配置属性来满足大部分验证规则,以下为一些常用配置,更多配置请查阅 [descriptor](/zh/api/descriptors/#descriptor)
116 |
117 | | 属性 | 类型 | 说明 |
118 | | --------- | ------------------------------- | ------------------------------------------------------------ |
119 | | required | Boolean | 字段是否为必填 |
120 | | pattern | RegExp | 用于匹配字段值的正则表达式 |
121 | | len | Number | 验证字符串或数组的长度 |
122 | | validator | Function(rule, value, callback) | 自定义校验函数, callback(Error)表示校验失败, callback()校验通过 |
123 |
124 |
125 |
126 | <<<@/docs/.vuepress/components/custom-validator.vue
127 |
128 | ### 自定义组件
129 |
130 | ::: tip 温馨提示
131 | 使用自定义组件功能,需保证 `组件版本 >= 2.5.0`
132 | :::
133 |
134 | **vue-dynamic-form-component** 内置了常见数据类型的组件,一般情况下你不需要自定义组件。但有些情况下我们确实需要自定义组件,为了满足特殊场景,提供了自定义组件的方式,例如,当我们想要使用单选框来代替下拉选择时,使用方式如下:
135 |
136 |
137 |
138 | <<<@/docs/.vuepress/components/custom-component.vue
139 |
140 | 组件内部使用 v-model 进行数据绑定,因此,当自定义组件可以使用 v-model ,则不需要进行特殊处理,直接更改组件名即可,descriptors 中的自定义组件格式:
141 |
142 | ``` json
143 | component: {
144 | name: 'el-radio-group', // 要使用的自定义组件名称
145 | props: {}, // 组件属性
146 | events: {}, // 绑定事件
147 | children: [], // 和组件相同的格式或者字符串表示纯文本节点
148 | }
149 | ```
150 |
151 | #### 非 v-model 组件
152 |
153 | 如果想要使用 el-image 这类非 v-model 组件,则需要自行封装一个组件来实现。新建一个自定义组件:
154 |
155 | ``` vue
156 |
157 |
158 |
159 |
160 |
161 |
162 |
182 | ```
183 |
184 | 全局注册该组件
185 |
186 | ``` js
187 | import MyImage from './MyImage'
188 | Vue.component(MyImage.name, MyImage)
189 | ```
190 |
191 | 之后就可以像上一步中一样使用该组件。
192 |
193 | 当然你也可以在自定义组件中添加更多的逻辑,例如图片加载失败时替换为默认值:
194 |
195 | ``` vue
196 |
197 |
198 |
199 |
200 |
201 |
202 |
227 | ```
228 |
229 | ### 表单操作
230 |
231 | **vue-dynamic-form-component** 提供了几个常用的方法来操作表单,可以配合 `operations` 插槽使用。
232 |
233 | ::: tip 温馨提示
234 | 为方便演示,文档中引入了 `el-button` 组件,如实际使用中需要,请自行引入。表单方法的具体参数请查阅 [组件方法](/zh/api/dynamic-form/#方法)。
235 | :::
236 |
237 |
238 |
239 | <<<@/docs/.vuepress/components/form-operation.vue{6,7,8,9,10}
240 |
241 |
--------------------------------------------------------------------------------
/docs/zh/guide/README.md:
--------------------------------------------------------------------------------
1 | # 介绍
2 |
3 | **vue-dynamic-form-component** 是一个基于 [element-ui](https://element.faas.ele.me/#/zh-CN) 和 [async-validator](https://github.com/yiminghe/async-validator) 实现的动态表单组件,支持嵌套Object/Hashmap/Array。只需要提供数据的描述器(参考[async-validator](https://github.com/yiminghe/async-validator)的descriptor),**vue-dynamic-form-component**就会自动生成对应的表单元素。
4 |
5 |
6 |
7 | ## 功能
8 |
9 | - 使用**descriptors**生成表单
10 | - 支持绝大部分数据类型
11 | - 支持**嵌套表单**,满足 `Object` / `Array` / `HashMap` 等复杂数据类型
12 | - 支持数据**校验**
13 | - **多语言**支持
14 | - 支持**自定义组件**
15 |
16 |
17 |
18 | ## 意见反馈
19 |
20 | 请通过 [Github Issue](https://github.com/chenquincy/vue-dynamic-form-component/issues) 提交您的意见反馈
21 |
22 |
23 |
24 | ## 开源证书
25 |
26 | [MIT license](https://tldrlegal.com/license/mit-license)
27 |
28 |
--------------------------------------------------------------------------------
/docs/zh/i18n/README.md:
--------------------------------------------------------------------------------
1 | # 多语言
2 |
3 | 组件内部默认使用中文,若希望使用其他语言,则需要进行多语言设置。
4 |
5 | ## element-ui配置
6 |
7 | 首先,由于组件的输入组件都来源于 `element-ui`,我们需要先设置 `element-ui` 的多语言配置,在 `main.js` 中:
8 |
9 | ``` js
10 | import Vue from 'vue'
11 | import ElementUI from 'element-ui'
12 | import locale from 'element-ui/lib/locale/lang/en'
13 |
14 | Vue.use(ElementUI, { locale })
15 | ```
16 |
17 | 更多的 `element-ui` 多语言配置可以查看 [element-ui多语言配置](https://element.faas.ele.me/#/zh-CN/component/i18n)
18 |
19 | ## 配置组件
20 |
21 | 组件默认自带了中文和英文语言包,可以通过 `lang` 属性切换
22 |
23 | ``` vue
24 |
25 |
29 |
30 |
31 | ```
32 |
33 | 属性取值对应表为
34 |
35 | | 语言 | 值 |
36 | | ---- | ----- |
37 | | 中文 | zh_CN |
38 | | 英文 | en_US |
39 |
40 | ### 自定义语言包
41 |
42 | 组件提供 `languages` 属性供用户自行扩展语言包,`languages` 格式如下:
43 |
44 | ``` js
45 | {
46 | 'zh_CN': {
47 | addKeyPlaceholder: '请输入您想要的键值',
48 | addKeyButtonText: '添加键值',
49 | addArrayItemButtonText: '添加元素'
50 | },
51 | 'en_US': {
52 | ...
53 | }
54 | }
55 | ```
56 |
57 | ``` html
58 |
59 |
64 |
65 |
66 | ```
67 |
68 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-dynamic-form-component",
3 | "version": "2.8.1",
4 | "license": "MIT",
5 | "author": {
6 | "email": "mail@quincychen.cn",
7 | "name": "quincychen",
8 | "url": "https://quincychen.cn"
9 | },
10 | "keywords": [
11 | "vue",
12 | "dynamic",
13 | "form",
14 | "component"
15 | ],
16 | "repository": {
17 | "type": "github",
18 | "url": "https://github.com/chenquincy/vue-dynamic-form-component"
19 | },
20 | "scripts": {
21 | "dev": "vue-cli-service serve",
22 | "build": "vue-cli-service build --target lib --dest lib --name vue-dynamic-form-component ./packages/index.js",
23 | "docs:dev": "vuepress dev docs",
24 | "docs:build": "vuepress build docs"
25 | },
26 | "main": "./lib/vue-dynamic-form-component.umd.min.js",
27 | "typings": "types/index.d.ts",
28 | "vetur": {
29 | "tags": "vetur/tags.json",
30 | "attributes": "vetur/attributes.json"
31 | },
32 | "peerDependencies": {
33 | "element-ui": "^2.11.1",
34 | "vue": "^2.6.10"
35 | },
36 | "devDependencies": {
37 | "@vue/cli-plugin-babel": "^3.8.0",
38 | "@vue/cli-plugin-eslint": "^3.8.0",
39 | "@vue/cli-service": "^3.8.0",
40 | "@vue/eslint-config-standard": "^4.0.0",
41 | "@vuepress/plugin-google-analytics": "^1.2.0",
42 | "babel-eslint": "^10.0.1",
43 | "element-ui": "^2.11.1",
44 | "eslint": "^5.16.0",
45 | "eslint-plugin-vue": "^5.0.0",
46 | "node-sass": "^7.0.0",
47 | "sass-loader": "^7.1.0",
48 | "vue": "^2.6.10",
49 | "vue-template-compiler": "^2.6.10",
50 | "vuepress": "^1.0.1",
51 | "vuepress-plugin-sitemap": "^2.1.2"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/packages/dynamic-component/component.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 | {{ component }}
10 |
11 |
12 |
44 |
45 |
47 |
--------------------------------------------------------------------------------
/packages/dynamic-component/index.js:
--------------------------------------------------------------------------------
1 | import DynamicComponent from './component.vue'
2 |
3 | DynamicComponent.install = function (Vue) {
4 | Vue.component(DynamicComponent.name, DynamicComponent)
5 | }
6 |
7 | export default DynamicComponent
8 |
--------------------------------------------------------------------------------
/packages/dynamic-form-item/form-item.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
29 |
40 |
41 |
42 |
43 |
69 |
70 |
71 |
72 |
73 |
77 |
78 |
79 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
230 |
231 |
267 |
--------------------------------------------------------------------------------
/packages/dynamic-form-item/index.js:
--------------------------------------------------------------------------------
1 | import component from './form-item.vue'
2 |
3 | component.install = function (Vue) {
4 | Vue.component(component.name, component)
5 | }
6 |
7 | export default component
8 |
--------------------------------------------------------------------------------
/packages/dynamic-form/form.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
194 |
195 |
208 |
--------------------------------------------------------------------------------
/packages/dynamic-form/index.js:
--------------------------------------------------------------------------------
1 | import component from './form.vue'
2 |
3 | component.install = function (Vue) {
4 | Vue.component(component.name, component)
5 | }
6 |
7 | export default component
8 |
--------------------------------------------------------------------------------
/packages/dynamic-input/index.js:
--------------------------------------------------------------------------------
1 | import DynamicInput from './input.vue'
2 |
3 | DynamicInput.install = function (Vue) {
4 | Vue.component(DynamicInput.name, DynamicInput)
5 | }
6 |
7 | export default DynamicInput
8 |
--------------------------------------------------------------------------------
/packages/dynamic-input/input.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
22 |
23 |
24 |
25 |
33 |
34 |
35 |
36 |
143 |
144 |
152 |
--------------------------------------------------------------------------------
/packages/i18n.js:
--------------------------------------------------------------------------------
1 | export default {
2 | en_US: {
3 | addKeyPlaceholder: 'Input the key you want to add',
4 | addKeyButtonText: 'Add Key',
5 | addArrayItemButtonText: 'Add Item'
6 | },
7 | zh_CN: {
8 | addKeyPlaceholder: '输入想要添加的字段名',
9 | addKeyButtonText: '添加',
10 | addArrayItemButtonText: '添加数据项'
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/packages/index.js:
--------------------------------------------------------------------------------
1 | import DynamicForm from './dynamic-form/index'
2 |
3 | const install = function (Vue) {
4 | if (install.installed) {
5 | return false
6 | }
7 | install.installed = true
8 | DynamicForm.install(Vue)
9 | }
10 |
11 | if (typeof window !== 'undefined' && window.Vue) {
12 | install(window.Vue)
13 | }
14 |
15 | export default DynamicForm
16 |
--------------------------------------------------------------------------------
/packages/utils.js:
--------------------------------------------------------------------------------
1 | export function isComplexType (type) {
2 | return ['object', 'array'].includes(type)
3 | }
4 |
5 | /**
6 | * get font length of string
7 | * @param {String} str
8 | */
9 | export function getStringLength (str) {
10 | let len = 0
11 | for (let i = 0; i < str.length; i++) {
12 | str.charCodeAt(i) > 255 ? len += 2 : len++
13 | }
14 | return Math.round(len / 2)
15 | }
16 |
17 | /**
18 | * get longest key's font length of object
19 | * @param {Object} object
20 | */
21 | export function getLabelWidth (descriptors, fontSize) {
22 | let maxLen = 0
23 | if (descriptors instanceof Array) {
24 | maxLen = getStringLength('Item ' + descriptors.length)
25 | } else {
26 | for (const key in descriptors) {
27 | if (descriptors[key]) {
28 | const typeDescriptor = findTypeDescriptor(descriptors[key])
29 | maxLen = Math.max(maxLen, getStringLength(typeDescriptor.label || key))
30 | } else {
31 | maxLen = Math.max(maxLen, getStringLength(key))
32 | }
33 | }
34 | }
35 | return `${maxLen * fontSize + 30}px` // add 30px for required char '*'
36 | }
37 |
38 | /**
39 | * darken color with offset
40 | * @param {String} color // HEX color
41 | * @param {Integer} offset // offset to darken, offset should >= 0
42 | */
43 | const DARKEST_COLOR = 150
44 | export function darkenColor (color, offset) {
45 | if (offset === 0) return color
46 | if (color[0] === '#') color = color.slice(1)
47 | offset = parseInt(offset)
48 | if (isNaN(offset)) return color
49 |
50 | offset = 0 - offset
51 | if (offset >= 0) return color
52 |
53 | const num = parseInt(color, 16)
54 | let r = (num >> 16) + offset
55 | let b = ((num >> 8) & 0x00FF) + offset
56 | let g = (num & 0x0000FF) + offset
57 |
58 | r = Math.max(DARKEST_COLOR, r)
59 | b = Math.max(DARKEST_COLOR, b)
60 | g = Math.max(DARKEST_COLOR, g)
61 |
62 | const newColor = g | (b << 8) | (r << 16)
63 | return `#${newColor.toString(16)}`
64 | }
65 |
66 | export function findTypeDescriptor (descriptor) {
67 | return descriptor instanceof Array ? descriptor.find(item => !!item.type) : descriptor
68 | }
69 |
70 | export function parseDescriptor (_descriptor) {
71 | let descriptor = findTypeDescriptor(_descriptor)
72 | if (['object', 'array'].includes(descriptor.type)) {
73 | if (descriptor.type === 'object') {
74 | // object
75 | if (descriptor.fields) {
76 | const data = {}
77 | for (const key in descriptor.fields) {
78 | data[key] = parseDescriptor(descriptor.fields[key])
79 | }
80 | return data
81 | } else if (descriptor.defaultField) {
82 | // object is a hashmap
83 | return {}
84 | }
85 | } else {
86 | // array
87 | return []
88 | }
89 | } else {
90 | return null
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {}
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | vue-dynamic-form-component
9 |
10 |
11 |
12 | We're sorry but vue-dynamic-form-component doesn't work properly without JavaScript enabled. Please enable it to continue.
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/public/vue-dynamic-form-component.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenquincy/vue-dynamic-form-component/8d061c21d7fb637a5117d3a65ee6cc438e348c48/public/vue-dynamic-form-component.gif
--------------------------------------------------------------------------------
/types/index.d.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 |
3 | export type ComponentSize = 'large' | 'medium' | 'small' | 'mini'
4 |
5 | export interface ValidateCallback {
6 | /**
7 | * The callback to tell the validation result
8 | *
9 | * @param isValid Whether the form is valid
10 | */
11 | (isValid: boolean): void
12 | }
13 |
14 | declare class DynamicForm extends Vue {
15 | /* binding value */
16 | value: object
17 | /* default language of component */
18 | lang: string
19 | /* language packages of component */
20 | languages: object
21 | /* descriptors of form, refer to https://github.com/yiminghe/async-validator */
22 | descriptors: object
23 | /* size of component */
24 | size: ComponentSize
25 | /* background color of component, default #FFFFFF */
26 | backgroundColor: string
27 | /* font size of component, default 14 */
28 | fontSize: number
29 | /* darken sub-form's background-color with offset while get positive integer, default 8 */
30 | bgColorOffset: number
31 | /**
32 | * Validate the whole form
33 | *
34 | * @param callback A callback to tell the validation result
35 | */
36 | validate (callback: ValidateCallback): void
37 | validate (): Promise
38 |
39 | /** reset all the fields and remove validation result */
40 | resetFields (): void
41 |
42 | /** clear validation message for certain fields */
43 | clearValidate (): void
44 | }
45 |
46 | export default DynamicForm
--------------------------------------------------------------------------------
/vetur/attributes.json:
--------------------------------------------------------------------------------
1 | {
2 | "value": {
3 | "description": "value of form"
4 | },
5 | "lang": {
6 | "options": ["zh_CN", "en_US", ""],
7 | "description": "Select the language of form or input the language key of custom languages, default: zh_CN"
8 | },
9 | "languages": {
10 | "description": "Custom language packages, format refer to the docs."
11 | },
12 | "descriptors": {
13 | "description": "FormData's descriptors, which will be used to generate the form."
14 | },
15 | "size": {
16 | "options": ["medium", "small", "mini"],
17 | "description": "Size of component, default: small."
18 | },
19 | "background-color": {
20 | "description": "Background color of form, default: #FFFFFF."
21 | },
22 | "font-size": {
23 | "description": "Font size of form(for compute label's width), default: 14."
24 | },
25 | "bg-color-offset": {
26 | "description": "Form background color offset(for distinguish the multi-level form), default 8."
27 | },
28 | "show-outer-error": {
29 | "type": "boolean",
30 | "description": "Whether show the error of the parent component, default: true"
31 | }
32 | }
--------------------------------------------------------------------------------
/vetur/tags.json:
--------------------------------------------------------------------------------
1 | {
2 | "dynamic-form": {
3 | "attributes": ["value", "lang", "languages", "descriptors", "size", "backgroundColor", "fontSize", "bgColorOffset", "showOuterError"],
4 | "defaults": ["v-model", "descriptors"],
5 | "description": "Generate form automatically by using descriptors."
6 | }
7 | }
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | lintOnSave: false,
3 | css: {
4 | extract: false
5 | },
6 | pages: {
7 | index: {
8 | entry: 'dev/main.js',
9 | template: 'public/index.html',
10 | filename: 'index.html'
11 | }
12 | },
13 | configureWebpack: config => {
14 | if (process.env.NODE_ENV === 'production') {
15 | config.externals = ['vue', 'Vue', 'element-ui', 'ElementUI']
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------