├── .browserslistrc ├── .editorconfig ├── .env.lib ├── .eslintrc.js ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── app ├── App.vue ├── main.js ├── router.js └── views │ ├── test-common │ ├── const.js │ └── index.vue │ └── test-extend │ ├── const.js │ └── index.vue ├── babel.config.js ├── deploy.sh ├── docs ├── .vuepress │ ├── components │ │ ├── add-item.vue │ │ ├── attrs │ │ │ └── select-side.vue │ │ ├── basic-validate.vue │ │ ├── code-contain.vue │ │ ├── custom-input.vue │ │ ├── custom │ │ │ └── custom-number.vue │ │ ├── dynamic-input.vue │ │ ├── expand-code-mirror.vue │ │ ├── layout-flexible.vue │ │ ├── layout-gutter.vue │ │ ├── layout-offset.vue │ │ ├── slot-front.vue │ │ ├── slot-label.vue │ │ ├── slot-rear.vue │ │ ├── slot-slot.vue │ │ ├── slot-tool.vue │ │ ├── slot-tooltip.vue │ │ └── validate-number.vue │ ├── config.js │ ├── enhanceApp.js │ ├── public │ │ └── element-schema-form__logo.jpg │ └── styles │ │ └── index.styl ├── README.md └── guide │ ├── README.md │ ├── component │ ├── README.md │ ├── SchemaForm.md │ ├── attr.md │ ├── custom.md │ ├── dynamic.md │ ├── expand.md │ ├── layout.md │ ├── schema.md │ └── slot.md │ ├── 在线示例.md │ ├── 快速开始.md │ └── 更新日志.md ├── lib ├── SchemaFormCodemirror.common.min.js ├── SchemaFormCodemirror.umd.min.js ├── SchemaFormQuill.common.min.js ├── SchemaFormQuill.umd.min.js ├── demo.html ├── element-schema-form.common.js ├── element-schema-form.umd.js └── element-schema-form.umd.min.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── favicon.ico └── index.html ├── rollup.config.js ├── src ├── components.js ├── index.js └── packages │ ├── SchemaForm.vue │ ├── SchemaFormItem.vue │ ├── components │ ├── SchemaFormCascader.vue │ ├── SchemaFormCheckbox.vue │ ├── SchemaFormColorpicker.vue │ ├── SchemaFormDatepicker.vue │ ├── SchemaFormInput.vue │ ├── SchemaFormPlaceholder.vue │ ├── SchemaFormProgress.vue │ ├── SchemaFormRadio.vue │ ├── SchemaFormRate.vue │ ├── SchemaFormSelect.vue │ ├── SchemaFormSlider.vue │ ├── SchemaFormSwitch.vue │ ├── SchemaFormTags.vue │ ├── SchemaFormTimepicker.vue │ ├── SchemaFormTimeselect.vue │ ├── schema-form-codemirror │ │ ├── SchemaFormCodemirror.vue │ │ └── index.js │ ├── schema-form-jsoneditor │ │ ├── SchemaFormJsoneditor.vue │ │ └── index.js │ └── schema-form-quill │ │ ├── SchemaFormQuill.vue │ │ └── index.js │ └── mixins │ ├── form-code-mirror-mixin.js │ ├── form-json-editor-mixin.js │ ├── form-mixin.js │ ├── form-tags-mixin.js │ └── layout-mixin.js └── vue.config.js /.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 | -------------------------------------------------------------------------------- /.env.lib: -------------------------------------------------------------------------------- 1 | NODE_ENV=production 2 | VUE_APP_BUILD_MODE=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 | /docs/.vuepress/dist 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | 15 | # Editor directories and files 16 | .idea 17 | .vscode 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw? 23 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [0.1.3](https://github.com/vueblocks/element-schema-form/compare/v0.1.2...v0.1.3) (2019-11-01) 2 | 3 | 4 | ### Bug Fixes 5 | 6 | * schema-form插槽错误 ([fe43fbb](https://github.com/vueblocks/element-schema-form/commit/fe43fbb4c47984f092254536eff93c800617e6e7)) 7 | 8 | 9 | 10 | ## [0.1.2](https://github.com/vueblocks/element-schema-form/compare/v0.1.1...v0.1.2) (2019-10-30) 11 | 12 | 13 | 14 | ## [0.1.1](https://github.com/vueblocks/element-schema-form/compare/v0.1.0...v0.1.1) (2019-10-29) 15 | 16 | 17 | ### Features 18 | 19 | * 新增【重置表单】功能 ([9da36a3](https://github.com/vueblocks/element-schema-form/commit/9da36a37cadf06bedabf4bbdb9994ac620fa13e3)) 20 | 21 | 22 | 23 | # [0.1.0](https://github.com/vueblocks/element-schema-form/compare/9c615890fe925a11c33f3b3534381332b9867cf7...v0.1.0) (2019-10-28) 24 | 25 | 26 | ### Bug Fixes 27 | 28 | * copy 激活行数调整,api将module修改为model ([d3682be](https://github.com/vueblocks/element-schema-form/commit/d3682be362dec1c3f96ee120fcebaf27664a75e4)) 29 | 30 | 31 | ### Features 32 | 33 | * 🌈完成生成 Vue 代码功能 ([215dac0](https://github.com/vueblocks/element-schema-form/commit/215dac0ce0987f5e59b3507a51f5431da59af09e)) 34 | * 💥引入 vuex-persistedstate 数据持久化插件 ([e825350](https://github.com/vueblocks/element-schema-form/commit/e825350561a37de53ecb78fa4d789bc7875ada5e)) 35 | * 📋添加复制代码到剪切板功能 ([8e069b3](https://github.com/vueblocks/element-schema-form/commit/8e069b36113d7357705d30acf77b208b4a8d70b9)) 36 | * 修改布局算法 ([0d38a49](https://github.com/vueblocks/element-schema-form/commit/0d38a493503b80369276d6756de037571ea9847d)) 37 | * 基础组件 ([9c61589](https://github.com/vueblocks/element-schema-form/commit/9c615890fe925a11c33f3b3534381332b9867cf7)) 38 | * 增加json编辑器 ([3887414](https://github.com/vueblocks/element-schema-form/commit/38874147675504d40a670bacd4373dd109bc5f45)) 39 | * 增加列跨度配置 ([b6d72c6](https://github.com/vueblocks/element-schema-form/commit/b6d72c60720645b02076466f3bbd67e215934b3e)) 40 | * 增加拓展组件 ([d635fdd](https://github.com/vueblocks/element-schema-form/commit/d635fdd40349e93eecda0f52a9c249d2b87b0a6a)) 41 | * 增加组件个性化属性(1) ([2ca9dc7](https://github.com/vueblocks/element-schema-form/commit/2ca9dc74b296f6d0de97d6493245cde3aeca5afe)) 42 | * 增加组件基础属性编辑 ([30d335e](https://github.com/vueblocks/element-schema-form/commit/30d335ebede61056ca1c5c941d673a638c14429c)) 43 | * 增加表单预览 ([a70c222](https://github.com/vueblocks/element-schema-form/commit/a70c2222bc5358cd2e440299d0acd78032649599)) 44 | * 处理左侧布局删除列逻辑 ([c047010](https://github.com/vueblocks/element-schema-form/commit/c04701062e7eb8fbc2b59f66b8675cb15c172c5e)) 45 | * 完成生成 Schema 功能 ([dcbe5c5](https://github.com/vueblocks/element-schema-form/commit/dcbe5c51500a3f6b63985597b275d954a464ac3c)) 46 | * 搭建表单生成器页面 ([62d3085](https://github.com/vueblocks/element-schema-form/commit/62d30855341080e3de09b4291263fca3228cd5e5)) 47 | * 新增/删除行 ([f99ad57](https://github.com/vueblocks/element-schema-form/commit/f99ad57357db78ba3fc4f31aaee6a61e17d1a49b)) 48 | * 新增tag等基本组件 ([3e8c38d](https://github.com/vueblocks/element-schema-form/commit/3e8c38d56962faeb4e9f13a28f9af1fa9b8b863e)) 49 | * 新增列排序功能 ([0a74c03](https://github.com/vueblocks/element-schema-form/commit/0a74c03c62e4ada86d98127566a8cb5449cc324e)) 50 | * 新增行复制 ([6698e11](https://github.com/vueblocks/element-schema-form/commit/6698e11a3505fa884026ccfe981d543b82086cb4)) 51 | * 新增表单列删除功能 ([c08c8c0](https://github.com/vueblocks/element-schema-form/commit/c08c8c0c44bdb3ed76d9fce333992069cfb972d6)) 52 | * 新增表单配置面板 ([ecdbee5](https://github.com/vueblocks/element-schema-form/commit/ecdbee5557f6cddfe28617939f189d4f9de61992)) 53 | * 私有属性调整 ([cf61919](https://github.com/vueblocks/element-schema-form/commit/cf6191953e5117db4138d255dfd438022c03ddf5)) 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Vue Blocks 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 | # element-schema-form 2 | 3 |

4 | 5 | 6 | 7 | 8 |

9 | 10 | A schema-based element-ui form component for Vue2.x. 11 | 12 | ## Installation 13 | 14 | ```bash 15 | npm i @vueblocks/element-schema-form -S 16 | ``` 17 | 18 | ## Document 19 | 20 | [https://vueblocks.github.io/element-schema-form/](https://vueblocks.github.io/element-schema-form/) 21 | 22 | ## Online Demo 23 | 24 | ### 表单验证 25 | 26 | [![Edit 表单验证](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/biaodanyanzheng-er1t1?fontsize=14&hidenavigation=1&theme=dark) 27 | 28 | ### 数字类型验证 29 | 30 | [![Edit 数字类型验证](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/shuzileixingyanzheng-eezhn?fontsize=14&hidenavigation=1&theme=dark) 31 | 32 | ### 动态增减表单项 33 | 34 | [![Edit 动态增减表单项](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/dongtaizengjianbiaodanxiang-h0ogx?fontsize=14&hidenavigation=1&theme=dark) 35 | 36 | ## License 37 | 38 | MIT -------------------------------------------------------------------------------- /app/App.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 41 | 42 | 57 | -------------------------------------------------------------------------------- /app/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | import 'normalize.css' 4 | 5 | import router from './router' 6 | 7 | import ElementUI from 'element-ui' 8 | import 'element-ui/lib/theme-chalk/index.css' 9 | 10 | import SchemaForm, { SchemaFormItem } from '../src/index' 11 | import SchemaFormJsoneditor from '../src/packages/components/schema-form-jsoneditor' 12 | import SchemaFormQuill from '../src/packages/components/schema-form-quill' 13 | import SchemaFormCodemirror from '../src/packages/components/schema-form-codemirror' 14 | // 引入codeMirror的样式 15 | import 'codemirror/lib/codemirror.css' 16 | import 'codemirror/theme/cobalt.css' 17 | import 'codemirror/mode/javascript/javascript.js' 18 | // 引入jsoneditor的样式 19 | import 'jsoneditor/dist/jsoneditor.min.css' 20 | 21 | import App from './App.vue' 22 | 23 | Vue.use(ElementUI, { 24 | size: 'small' 25 | }) 26 | Vue.component('SchemaFormJsoneditor', SchemaFormJsoneditor) 27 | Vue.component('SchemaFormQuill', SchemaFormQuill) 28 | Vue.component('SchemaFormCodemirror', SchemaFormCodemirror) 29 | 30 | Vue.component('SchemaFormItem', SchemaFormItem) 31 | 32 | Vue.use(SchemaForm, { 33 | 'codemirror': { 34 | cmOptions: { 35 | tabSize: 2, 36 | mode: 'text/javascript', 37 | theme: 'cobalt', 38 | lineNumbers: true, 39 | line: true 40 | } 41 | }, 42 | input: { 43 | placeholder: '全局定义变量实验' 44 | } 45 | }) 46 | 47 | Vue.config.productionTip = false 48 | 49 | new Vue({ 50 | router, 51 | render: h => h(App) 52 | }).$mount('#app') 53 | -------------------------------------------------------------------------------- /app/router.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | 4 | Vue.use(Router) 5 | 6 | export default new Router({ 7 | routes: [ 8 | { 9 | path: '/', 10 | redirect: '/test-common' 11 | }, 12 | { 13 | path: '/test-common', 14 | component: () => import('@/views/test-common/index.vue') 15 | }, 16 | { 17 | path: '/test-extend', 18 | component: () => import('@/views/test-extend/index.vue') 19 | } 20 | ] 21 | }) 22 | -------------------------------------------------------------------------------- /app/views/test-common/const.js: -------------------------------------------------------------------------------- 1 | export const model = { 2 | name: 'lk', 3 | age: '18', 4 | phone: '', 5 | sex: 'male', 6 | expire: '', 7 | location: [], 8 | isOn: false, 9 | city: ['beijing'], 10 | sliderVal: 60, 11 | sleepTime: '', 12 | star: 0, 13 | color: '#409EFF', 14 | label: ['小清新'], 15 | percent: 20 16 | } 17 | export const schema = [ 18 | [ 19 | { 20 | type: 'input', 21 | prop: 'name', 22 | formItem: { label: '电话' }, 23 | attrs: { placeholder: '测试优先级' }, 24 | colGrid: { span: 8 }, 25 | labelSlot: 'inputName' 26 | }, { 27 | type: 'input', 28 | prop: 'age', 29 | formItem: { label: '年龄' }, 30 | colGrid: { span: 8 }, 31 | labelTooltip: '初三' 32 | } 33 | ], 34 | [ 35 | { 36 | type: 'select', 37 | prop: 'phone', 38 | formItem: { label: '电话' } 39 | }, 40 | { 41 | type: 'radio', 42 | prop: 'sex', 43 | formItem: { label: '性别' } 44 | }, { 45 | type: 'datepicker', 46 | prop: 'expire', 47 | formItem: { label: '有效期' }, 48 | attrs: { 49 | type: 'monthrange', 50 | 'range-separator': '至', 51 | 'start-placeholder': '开始月份', 52 | 'end-placeholder': '结束月份' 53 | } 54 | } 55 | ], 56 | [ 57 | { type: 'cascader', 58 | prop: 'location', 59 | formItem: { label: '地域' }, 60 | attrs: { 'show-all-levels': false } 61 | }, { 62 | type: 'switch', 63 | prop: 'isOn', 64 | formItem: { label: '开关' } 65 | }, { 66 | type: 'checkbox', 67 | prop: 'city', 68 | formItem: { label: '地域' } 69 | } 70 | ], 71 | [ 72 | { 73 | type: 'slider', 74 | prop: 'sliderVal', 75 | formItem: { label: '成绩' }, 76 | attrs: { 'show-stops': true, step: 10 } 77 | }, { 78 | type: 'timepicker', 79 | prop: 'sleepTime', 80 | formItem: { label: '晚睡时间' }, 81 | attrs: { 82 | 'picker-options': { 83 | selectableRange: '18:30:00 - 20:30:00' 84 | }, 85 | 'arrow-control': true 86 | } 87 | }, { 88 | type: 'rate', 89 | prop: 'star', 90 | formItem: { label: '观影得分' } 91 | } 92 | ], 93 | [ 94 | { 95 | type: 'colorpicker', 96 | prop: 'color', 97 | formItem: { label: '颜色' } 98 | }, { 99 | type: 'tags', 100 | prop: 'label', 101 | formItem: { label: '标签' }, 102 | attrs: { size: 'medium', buttonSize: 'mini', 'show-add': true } 103 | }, { 104 | type: 'progress', 105 | prop: 'percent', 106 | formItem: { label: '进度' } 107 | } 108 | ] 109 | ] 110 | export const options = { 111 | phone: [{ label: '1881031****', value: '1881031****' }, { label: '1861031****', value: '1861031****' }], 112 | sex: [{ label: '男', value: 'male' }, { label: '女', value: 'female' }], 113 | location: [ 114 | { label: '北京', value: 'beijing', children: [{ label: '通州', value: 'tongzhou' }] }, 115 | { label: '天津', value: 'tianjin' } 116 | ], 117 | city: [ 118 | { label: '北京', value: 'beijing' }, 119 | { label: '上海', value: 'shanghai' }, 120 | { label: '广州', value: '广州', disabled: true } 121 | ] 122 | } 123 | -------------------------------------------------------------------------------- /app/views/test-common/index.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 57 | 58 | 61 | -------------------------------------------------------------------------------- /app/views/test-extend/const.js: -------------------------------------------------------------------------------- 1 | export const model = { 2 | json: { 3 | a: 10, 4 | b: 20, 5 | customer: 10 6 | }, 7 | quill: '

一段文字

', 8 | code: 'let a = 100' 9 | } 10 | export const schema = [ 11 | [ 12 | { 13 | type: 'jsoneditor', 14 | prop: 'json', 15 | frontSlot: 'json', 16 | formItem: { label: '' }, 17 | attrs: { mode: 'code' } 18 | } 19 | ], 20 | [ 21 | { 22 | type: 'quill', 23 | prop: 'quill', 24 | formItem: { label: '富文本编辑' }, 25 | attrs: { 'editor-toolbar': [ 26 | ['bold', 'italic', 'underline'], 27 | [{ list: 'ordered' }, { list: 'bullet' }], 28 | ['code-block']] 29 | } 30 | } 31 | ], 32 | [ 33 | { 34 | type: 'codemirror', 35 | prop: 'code', 36 | formItem: { label: '代码镜像' } 37 | } 38 | ] 39 | ] 40 | export const options = {} 41 | -------------------------------------------------------------------------------- /app/views/test-extend/index.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 77 | 78 | 85 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | const plugins = [ 2 | 'lodash', 3 | [ 4 | 'component', 5 | { 6 | 'libraryName': 'element-ui', 7 | 'styleLibraryName': '~theme' 8 | } 9 | ] 10 | ] 11 | 12 | // 生产模式使用 transform-remove-console 插件 13 | if (process.env.NODE_ENV === 'production') { 14 | plugins.push('transform-remove-console') 15 | } 16 | 17 | module.exports = { 18 | presets: [ 19 | '@vue/cli-plugin-babel/preset' 20 | ], 21 | plugins 22 | } 23 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 确保脚本抛出遇到的错误 4 | set -e 5 | 6 | # 生成静态文件 7 | npm run docs:build 8 | 9 | # 进入生成的文件夹 10 | cd docs/.vuepress/dist 11 | 12 | # 如果是发布到自定义域名 13 | # echo 'www.example.com' > CNAME 14 | 15 | git init 16 | git add -A 17 | git commit -m 'chore: deploy docs' 18 | 19 | # 如果发布到 https://.github.io 20 | # git push -f git@github.com:/.github.io.git master 21 | 22 | # 如果发布到 https://.github.io/ 23 | git push -f https://github.com/vueblocks/element-schema-form.git master:gh-pages 24 | 25 | cd - -------------------------------------------------------------------------------- /docs/.vuepress/components/add-item.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 89 | 90 | -------------------------------------------------------------------------------- /docs/.vuepress/components/attrs/select-side.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 43 | 44 | 52 | -------------------------------------------------------------------------------- /docs/.vuepress/components/basic-validate.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 137 | 138 | -------------------------------------------------------------------------------- /docs/.vuepress/components/code-contain.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 75 | 76 | 81 | 82 | -------------------------------------------------------------------------------- /docs/.vuepress/components/custom-input.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 30 | 31 | 34 | -------------------------------------------------------------------------------- /docs/.vuepress/components/custom/custom-number.vue: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 20 | 21 | -------------------------------------------------------------------------------- /docs/.vuepress/components/dynamic-input.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 44 | 45 | 48 | -------------------------------------------------------------------------------- /docs/.vuepress/components/expand-code-mirror.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 46 | 47 | 50 | -------------------------------------------------------------------------------- /docs/.vuepress/components/layout-flexible.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 37 | 38 | -------------------------------------------------------------------------------- /docs/.vuepress/components/layout-gutter.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 37 | 38 | -------------------------------------------------------------------------------- /docs/.vuepress/components/layout-offset.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 38 | 39 | -------------------------------------------------------------------------------- /docs/.vuepress/components/slot-front.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 38 | 39 | 42 | -------------------------------------------------------------------------------- /docs/.vuepress/components/slot-label.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 37 | 38 | 43 | -------------------------------------------------------------------------------- /docs/.vuepress/components/slot-rear.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 36 | 37 | 45 | -------------------------------------------------------------------------------- /docs/.vuepress/components/slot-slot.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 28 | 29 | 32 | -------------------------------------------------------------------------------- /docs/.vuepress/components/slot-tool.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 33 | 34 | 39 | -------------------------------------------------------------------------------- /docs/.vuepress/components/slot-tooltip.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 34 | 35 | 40 | -------------------------------------------------------------------------------- /docs/.vuepress/components/validate-number.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 56 | 57 | -------------------------------------------------------------------------------- /docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | title: 'Element Schema Form', 3 | description: '基于 JSON Schema 构建 Element 表单,表单页面开发从未如此高效', 4 | base: '/element-schema-form/', 5 | port: 5454, 6 | themeConfig: { 7 | sidebarDepth: 2, 8 | nav: [ 9 | { text: '指南', link: '/guide/' }, 10 | { text: '组件', link: '/guide/component/SchemaForm/' }, 11 | { 12 | text: '表单设计器', 13 | link: 'https://vueblocks.github.io/element-form-generator/' 14 | }, 15 | { 16 | text: 've-charts', 17 | link: 'https://github.com/vueblocks/ve-charts' 18 | }, 19 | { 20 | text: 'GitHub', 21 | link: 'https://github.com/vueblocks/element-schema-form' 22 | }, 23 | ], 24 | sidebar: { 25 | '/guide/': [ 26 | { 27 | title: '指南', 28 | collapsable: false, 29 | children: [ 30 | '', 31 | '快速开始', 32 | '更新日志', 33 | '在线示例', 34 | ] 35 | }, 36 | { 37 | title: '组件', 38 | collapsable: false, 39 | sidebarDepth: 1, 40 | children: [ 41 | '/guide/component/SchemaForm', 42 | ['/guide/component/schema', 'schema 详解'], 43 | ['/guide/component/layout', 'layout 布局'], 44 | ['/guide/component/slot', 'slot 插槽'], 45 | ['/guide/component/dynamic', 'dynamicAttrs 动态属性'], 46 | ['/guide/component/custom', '自定义组件'], 47 | ['/guide/component/expand', '第三方拓展'], 48 | ['/guide/component/attr', '拓展属性'] 49 | ] 50 | } 51 | ] 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /docs/.vuepress/enhanceApp.js: -------------------------------------------------------------------------------- 1 | import SchemaForm from '../../src/index.js' 2 | import ElementUI from "element-ui" 3 | import CustomNumber from './components/custom/custom-number.vue' 4 | 5 | import "element-ui/lib/theme-chalk/index.css" 6 | import '@vuepress/theme-default' 7 | 8 | 9 | export default ({ Vue }) => { 10 | Vue.use(SchemaForm) 11 | Vue.use(ElementUI) 12 | // Vue.use(SchemaFormQuill) 13 | Vue.component('CustomNumber', CustomNumber) 14 | } 15 | -------------------------------------------------------------------------------- /docs/.vuepress/public/element-schema-form__logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vueblocks/element-schema-form/ff2a3ae205d3034d0dd38ab666c68eb2171cc2de/docs/.vuepress/public/element-schema-form__logo.jpg -------------------------------------------------------------------------------- /docs/.vuepress/styles/index.styl: -------------------------------------------------------------------------------- 1 | 2 | table thead th { 3 | color: #909399; 4 | font-size: 14px; 5 | } 6 | table tbody td { 7 | color: #606266; 8 | font-size: 14px; 9 | } -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | heroImage: /element-schema-form__logo.jpg 4 | actionText: 快速开始 → 5 | actionLink: /guide/ 6 | features: 7 | - title: JSON Schema Based 8 | details: 基于 JSON Schema 规范的数据驱动 9 | - title: Element UI Based 10 | details: 基于 Element UI 组件库的 Form 表单 11 | - title: Responsive Form 12 | details: 灵活的响应式的栅格表单布局 13 | footer: MIT Licensed | Copyright © 2019-present VueBlocks 14 | --- -------------------------------------------------------------------------------- /docs/guide/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | { 3 | "title": "介绍", 4 | } 5 | --- 6 | 7 | ## 背景 8 | 9 | 前端领域里,在中后台实际业务场景中,基本上逃不过表单页面的开发,表单页面承担着数据输入的角色,是数据收集的重要来源。 10 | 11 | 而对于工程中使用 **Element** 作为UI组件库的项目而言,前端开发者在使用 `el-form` 的时候可能更多的都在关注: 12 | 13 | * 如何布局表单 14 | * 表单控件类型 15 | * 表单控件配置项 16 | * 表单的状态管理 17 | * 表单校验 18 | 19 | 从而为了实现一个业务场景复杂的表单,往往要编写大量重复的代码,以及产生篇幅巨大的单页面组件,而这样的开发方式是不必要的。 20 | 21 | ## 方案 22 | 23 | 经过我们在表单领域的不断探索与尝试,总结出了一套基于 **JSON Schema** 规范的数据动态生成表单的解决方案 **Element Schema Form**。 24 | 25 | **Element Schema Form** 是一个基于 `Vue`、`element-ui` 技术栈封装的表单组件,用于解决大型、复杂表单页面开发过程中所做的大量重复性工作。使用一份 JSON Schema 即可生成一个成型的 form 表单,使表单组件代码变得简洁并便于维护。开发表单更高效。 26 | 27 | ## 核心功能 28 | 29 | * 基于 JSON Schema 的数据结构生成表单 30 | * 基于 `el-row`/`el-col` 的灵活表单布局 31 | * 支持所有 `element-ui` 基础表单组件 32 | * 支持常用第三方扩展组件,如 `codemirror`、`quill editor`、`markdown editor` 等 33 | * 支持个性化的自定义插槽组件 34 | * 支持可视化构建表单 35 | 36 | ## JSON Schema 规范 37 | 38 | 如果你还不了解什么是 JSON Schema,请移步这里 [JSON Schema](https://json-schema.org/) 39 | 40 | ## 可视化探索 41 | 42 | 为了开发更高效,我们提供了基于 **Element Schema Form** 开发的可视化配置工具 43 | 44 | 表单设计器 [element-form-generator](https://github.com/vueblocks/element-form-generator) 45 | 46 | 只需简单操作几步即可配置好一个 form 表单 47 | -------------------------------------------------------------------------------- /docs/guide/component/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | { 3 | "title": "组件", 4 | } 5 | --- -------------------------------------------------------------------------------- /docs/guide/component/SchemaForm.md: -------------------------------------------------------------------------------- 1 | --- 2 | { 3 | "title": "SchemaForm", 4 | } 5 | --- 6 | 7 | 8 | ## 组件使用 9 | 10 | ```vue 11 | 22 | 23 | 39 | ``` 40 | 41 | ## Props 42 | 43 | ### layout 44 | 45 | #### 表单布局信息,详见 [layout布局](layout.html) 46 | 47 | 48 | ### model 49 | 50 | #### 表单数据对象,表单绑定值的集合,例如 51 | ``` js 52 | { 53 | model: { 54 | name: '', 55 | age: '' 56 | } 57 | } 58 | ``` 59 | 60 | ### schema 61 | #### 表单模板,用于表单的构建。详情见 [schema 详解](schema.html) 62 | 63 | 参数|说明|类型|可选值|默认值 64 | :--|:--|:--|:--|:-- 65 | prop|数据字段|string|-|- 66 | type|组件类型|string|-|- 67 | formItem|表单属性|object|-|- 68 | modifier|修饰符|string|number,trim|- 69 | attrs|组件属性|object|-|- 70 | dynamicAttrs|组件动态属性| object|-|- 71 | on|组件事件|object|-|- 72 | hide|是否隐藏|boolean|-|false 73 | colGrid|栅格布局,与el-col属性相同|object|-|- 74 | 75 | ### options 76 | 77 | #### 表单可选数据源,如我们常用的 el-select 的数据源 78 | ``` js 79 | { 80 | options: { 81 | foods: [ 82 | { 83 | value: '选项1', 84 | label: '黄金糕' 85 | }, { 86 | value: '选项2', 87 | label: '双皮奶' 88 | }] 89 | } 90 | } 91 | ``` -------------------------------------------------------------------------------- /docs/guide/component/attr.md: -------------------------------------------------------------------------------- 1 | ### 拓展属性 2 | 3 | ### select 拓展 4 | 5 | 新增 `optionSides` 属性,用于适应下拉框中展示多种属性 6 | 7 | 8 | <<< @/docs/.vuepress/components/attrs/select-side.vue 9 | 10 | -------------------------------------------------------------------------------- /docs/guide/component/custom.md: -------------------------------------------------------------------------------- 1 | ### 自定义组件 2 | 3 | SchemaForm 组件提供了便于创建自定义组件的方案,使用 `FormMixin` 创建你的自定义组件 4 | 5 | #### 创建自定义组件 6 | 7 | ``` vue 8 | // @/components/CustomNumber.vue 9 | 16 | 17 | 24 | ``` 25 | 26 | #### main.js 全局引入组件 27 | 28 | ``` js 29 | import ElementUI from 'element-ui' 30 | import 'element-ui/lib/theme-chalk/index.css' 31 | import SchemaForm from '@vueblocks/element-schema-form' 32 | import CustomNumber from '@/components/CustomNumber.vue' 33 | 34 | Vue.use(ElementUI) 35 | Vue.use(SchemaForm) 36 | Vue.component('CustomNumber', CustomNumber) 37 | ``` 38 | 39 | #### 使用自定义组件 40 | 41 | 42 | <<< @/docs/.vuepress/components/custom-input.vue 43 | -------------------------------------------------------------------------------- /docs/guide/component/dynamic.md: -------------------------------------------------------------------------------- 1 | ### 使用动态属性联动 2 | 3 | 4 | <<< @/docs/.vuepress/components/dynamic-input.vue 5 | -------------------------------------------------------------------------------- /docs/guide/component/expand.md: -------------------------------------------------------------------------------- 1 | ## codemirror 2 | 3 | 基于 [vue-codemirror-lite](https://github.com/cnu4/vue-codemirror-lite) 拓展的组件 4 | 5 | 安装组件依赖 6 | ``` js 7 | npm i vue-codemirror-lite -S 8 | ``` 9 | main.js 按需引入 SchemaFormCodemirror 组件, 语言模式和主题 10 | 11 | ``` js 12 | import SchemaFormCodemirror from '@vueblocks/element-schema-form/lib/SchemaFormCodemirror.common.min.js' 13 | 14 | import 'codemirror/lib/codemirror.css' 15 | import 'codemirror/theme/night.css' // theme: night 16 | import 'codemirror/mode/javascript/javascript.js' // mode: text/javascript 17 | 18 | Vue.use(SchemaFormCodemirror) 19 | ``` 20 | 21 | <<< @/docs/.vuepress/components/expand-code-mirror.vue 22 | 23 | 查看 [CodeMirror Manual](https://codemirror.net/doc/manual.html#modloader) 了解更多配置和主题 24 | 25 | ## quill 26 | 27 | 基于 [vue2-editor](https://github.com/davidroyer/vue2-editor) 拓展的组件 28 | 29 | 安装组件依赖 30 | ``` js 31 | npm i vue2-editor -S 32 | ``` 33 | main.js 按需引入 SchemaFormQuill 组件 34 | 35 | ``` js 36 | import SchemaFormQuill from '@vueblocks/element-schema-form/lib/SchemaFormQuill.common.min.js' 37 | 38 | Vue.use(SchemaFormQuill) 39 | ``` 40 | 41 | 使用 42 | ``` js 43 | 52 | 53 | 76 | ``` -------------------------------------------------------------------------------- /docs/guide/component/layout.md: -------------------------------------------------------------------------------- 1 | 2 | ### 简介 3 | 4 | SchemaForm 整体布局采用 el-row 和 el-col 进行封装, 通过基础的24分栏,迅速简便地创建布局 5 | 6 | ### 分栏间隔 7 | 8 | 9 | <<< @/docs/.vuepress/components/layout-gutter.vue 10 | 11 | 12 | ### 分栏偏移 13 | 14 | 15 | <<< @/docs/.vuepress/components/layout-offset.vue 16 | 17 | 18 | ### 响应式布局 19 | 20 | 21 | <<< @/docs/.vuepress/components/layout-flexible.vue 22 | 23 | 24 | ### layout Attributes 25 | 26 | 参数|说明|类型|可选值|默认值 27 | :--|:--|:--|:--|:--| 28 | gutter|栅格间隔|number|—|0 29 | type|布局模式,可选 flex,现代浏览器下有效|string|—|— 30 | justify|flex布局下的水平排列方式|string|start/end/center/space-around/space-between|start 31 | align|flex布局下的垂直排列方式|string|top/middle/bottom|top 32 | tag|自定义元素标签|string|*|div 33 | 34 | ### colGrid Attributes 35 | 36 | 参数|说明|类型|可选值|默认值 37 | :--|:--|:--|:--|:--| 38 | span|栅格占据的列数|number|—|24 39 | offset|栅格左侧的间隔格数|number|—|0 40 | push|栅格向右移动格数|number|—|0 41 | pull|栅格向左移动格数|number|—|0 42 | xs|<768px|响应式栅格数或者栅格属性对象|number/object (例如: {span: 4, offset: 4})|—|— 43 | sm|≥768px|响应式栅格数或者栅格属性对象|number/object (例如: {span: 4, offset: 4})|—|— 44 | md|≥992px|响应式栅格数或者栅格属性对象|number/object (例如: {span: 4, offset: 4})|—|— 45 | lg|≥1200px|响应式栅格数或者栅格属性对象|number/object (例如: {span: 4, offset: 4})|—|— 46 | xl|≥1920px|响应式栅格数或者栅格属性对象|number/object (例如: {span: 4, offset: 4})|—|— 47 | tag|自定义元素标签|string * div 48 | -------------------------------------------------------------------------------- /docs/guide/component/schema.md: -------------------------------------------------------------------------------- 1 | ## 数据字段 prop 2 | 3 | > prop 是辨别当前组件的唯一字段,既是 ```model 和 options 的键值 key ```,又是```el-form``` 使用 ```validate、resetFields``` 方法的必填字段,所以需保证 prop的 唯一性 4 | 5 | ## 组件类型 type 6 | 7 | > SchemaForm 的组件是基于 Element 进行封装,目标是完美兼容原组件的所有属性 8 | 9 | ### 内置类型 10 | 11 | 类型|含义|属性参考 12 | :--|:--|:-- 13 | input| 输入框 | [el-input](https://element.eleme.cn/#/zh-CN/component/input) 14 | select| 选择器 | [el-select](https://element.eleme.cn/#/zh-CN/component/select) 15 | radio| 单选框组 | [el-radio-group](https://element.eleme.cn/#/zh-CN/component/radio) 16 | checkbox| 多选框组 | [el-checkbox-group](https://element.eleme.cn/#/zh-CN/component/checkbox) 17 | cascader| 级联选择器 | [el-cascader](https://element.eleme.cn/#/zh-CN/component/cascader) 18 | switch| 开关 | [el-switch](https://element.eleme.cn/#/zh-CN/component/switch) 19 | slider| 滑块 | [el-slider](https://element.eleme.cn/#/zh-CN/component/slider) 20 | datepicker| 日期选择器 | [el-date-picker](https://element.eleme.cn/#/zh-CN/component/date-picker) 21 | timeselect| 固定时间 | [el-time-select](https://element.eleme.cn/#/zh-CN/component/time-picker) 22 | timepicker| 任意时间 | [el-time-picker](https://element.eleme.cn/#/zh-CN/component/time-picker) 23 | colorpicker| 颜色选择器 | [el-color-picker](https://element.eleme.cn/#/zh-CN/component/color-picker) 24 | progress| 进度条 | [el-progress](https://element.eleme.cn/#/zh-CN/component/progress) 25 | rate| 评分 | [el-rate](https://element.eleme.cn/#/zh-CN/component/rate) 26 | 27 | ## 表单属性 formItem 28 | 29 | > 兼容所有el-form-item的属性,以下内容为常用属性 30 | 31 | 参数|说明|类型|可选值|默认值 32 | :--|:--|:--|:--|:-- 33 | label|标签文本|string|—|— 34 | label-width|表单域标签的的宽度,例如 '50px'。支持 auto|string|—|— 35 | show-message|是否显示校验错误信息|boolean|—|true 36 | inline-message|以行内形式展示校验信息|boolean|—|false 37 | size|用于控制该表单域下组件的尺寸|string|medium / small / mini|- 38 | 39 | ## 绑定值修饰符 modifier 40 | 41 | > 为了更好的支持数值绑定,增加了```v-model```的修饰符,现支持 42 | 43 | 参数|说明 44 | :--|:-- 45 | number|自动将用户的输入值转为数值类型 46 | trim|自动过滤用户输入的首尾空白字符 47 | 48 | ## 属性绑定 attrs 49 | 50 | > 支持Element组件的属性,以```el-input```为例,具体参数 可参考 [Element](https://element.eleme.cn/#/zh-CN) 51 | 52 | ``` js 53 | { 54 | type: 'input', 55 | prop: 'name', 56 | attrs: { type: 'textarea' } 57 | } 58 | ``` 59 | 60 | ## 动态属性绑定 dynamicAttrs 61 | 62 | > 除了绑定的静态属性外,还支持动态属性的绑定,例如用于与其它操作联动 63 | 64 | ``` js 65 | { 66 | type: 'input', 67 | prop: 'name', 68 | dynamicAttrs: { disabled: !!this.model.id } 69 | } 70 | ``` 71 | 72 | ## 事件绑定 on 73 | 74 | > 支持Element组件的事件,以```el-input```为例,具体参数 可参考 [Element](https://element.eleme.cn/#/zh-CN) 75 | 76 | ``` js 77 | { 78 | type: 'input', 79 | prop: 'name', 80 | on: { focus: this.onNameFocus } 81 | } 82 | ``` 83 | 84 | ### 事件 & 按键修饰符 85 | 86 | > 对于 .passive、.capture 和 .once 这些事件修饰符, Vue 提供了相应的前缀可以用于 on 87 | 88 | 修饰符|前缀 89 | :--|:-- 90 | .passive|& 91 | .capture|! 92 | .once|~ 93 | .capture.once 或 .once.capture|~! 94 | 95 | ``` js 96 | on: { 97 | '!click': this.doThisInCapturingMode, 98 | '~keyup': this.doThisOnce, 99 | '~!mouseover': this.doThisOnceInCapturingMode 100 | } 101 | ``` 102 | 103 | > 对于所有其它的修饰符,私有前缀都不是必须的,因为你可以在事件处理函数中使用事件方法: 104 | 105 | ``` js 106 | on: { 107 | keyup: function (event) { 108 | // .self 等价于 如果触发事件的元素不是事件绑定的元素则返回 109 | if (event.target !== event.currentTarget) return 110 | // 如果按下去的不是 enter 键或者 111 | // 没有同时按下 shift 键 112 | // 则返回 113 | if (!event.shiftKey || event.keyCode !== 13) return 114 | // 阻止 事件冒泡 115 | event.stopPropagation() 116 | // 阻止该元素默认的 keyup 事件 117 | event.preventDefault() 118 | // ... 119 | } 120 | } 121 | ``` 122 | 123 | ## 插槽 slot 124 | 125 | 参数|说明| 126 | :--|:-- 127 | slot| 自定义完整组件 128 | labelSlot| 用于 el-form-item 中的 label插槽 129 | frontSlot| 定义element 组件前的插槽 130 | rearSlot| 定义element 组件后的插槽 131 | -------------------------------------------------------------------------------- /docs/guide/component/slot.md: -------------------------------------------------------------------------------- 1 | ### 插槽 2 | 3 | 4 | <<< @/docs/.vuepress/components/slot-slot.vue 5 | 6 | 7 | ### 前置插槽 8 | 9 | 10 | <<< @/docs/.vuepress/components/slot-front.vue 11 | 12 | 13 | ### 后置插槽 14 | 15 | 16 | <<< @/docs/.vuepress/components/slot-rear.vue 17 | 18 | 19 | 20 | ### 标签插槽 21 | 22 | 23 | <<< @/docs/.vuepress/components/slot-label.vue 24 | 25 | 26 | ### 自定义前置/后置文本 27 | 28 | <<< @/docs/.vuepress/components/slot-tool.vue 29 | 30 | 31 | ### 自定义标题说明 32 | 33 | <<< @/docs/.vuepress/components/slot-tooltip.vue 34 | -------------------------------------------------------------------------------- /docs/guide/在线示例.md: -------------------------------------------------------------------------------- 1 | --- 2 | { 3 | "title": "在线示例", 4 | } 5 | --- 6 | 7 | ### 表单验证 8 | 9 | 10 | <<< @/docs/.vuepress/components/basic-validate.vue 11 | 12 | 13 | ### 数字类型验证 14 | 15 | 16 | <<< @/docs/.vuepress/components/validate-number.vue 17 | 18 | 19 | ### 动态增减表单项 20 | 21 | 22 | <<< @/docs/.vuepress/components/add-item.vue 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /docs/guide/快速开始.md: -------------------------------------------------------------------------------- 1 | --- 2 | { 3 | "title": "快速开始", 4 | } 5 | --- 6 | 7 | ## 安装 8 | 9 | ```bash 10 | npm i @vueblocks/element-schema-form -S 11 | ``` 12 | 13 | or 14 | 15 | ```bash 16 | yarn add @vueblocks/element-schema-form 17 | ``` 18 | 19 | ## 引入组件 20 | 21 | 完整引入 22 | 23 | ```js 24 | import SchemaForm from '@vueblocks/element-schema-form' 25 | 26 | Vue.use(SchemaForm) 27 | ``` 28 | 29 | ## 引入第三方扩展 30 | 31 | `SchemaForm` 支持一些用于表单渲染的高级组件 32 | 33 | 例如 `codemirror`,使用前需要安装组件依赖 34 | 35 | ```bash 36 | npm i codemirror vue-codemirror-lite -S 37 | ``` 38 | 39 | 按需引入 `SchemaFormCodemirror` 组件 40 | 41 | ```js 42 | import SchemaFormCodemirror from '@vueblocks/element-schema-form/lib/SchemaFormCodemirror.common.min' 43 | 44 | Vue.component('SchemaFormCodemirror', SchemaFormCodemirror) 45 | ``` 46 | 47 | ## 组件预设配置 48 | 49 | ```js 50 | // input 输入框 placeholder 预设 51 | Vue.use(SchemaForm, { 52 | input: { 53 | placeholder: '全局定义变量实验' 54 | } 55 | }) 56 | 57 | // codemirror 插件配置项预设 58 | Vue.use(SchemaForm, { 59 | 'codemirror': { 60 | cmOptions: { 61 | tabSize: 2, 62 | mode: 'text/javascript', 63 | theme: 'cobalt', 64 | lineNumbers: true, 65 | line: true 66 | } 67 | } 68 | }) 69 | ``` 70 | -------------------------------------------------------------------------------- /docs/guide/更新日志.md: -------------------------------------------------------------------------------- 1 | --- 2 | { "title": "更新日志" } 3 | --- 4 | 5 | ## 0.1.8 (2021-10-25) 6 | 7 | - select 选择器拓展 `optionSides`, 丰富下拉展示 8 | 9 | ## 0.1.7 (2021-02-20) 10 | 11 | - 增加新属性 labelTooltip, 用于自定义标题的说明 12 | - 增加标签插槽 labelSlot 13 | 14 | ## 0.1.6 (2021-01-22) 15 | 16 | ### feat 17 | 18 | - 增加属性 rearHtml、frontHtml ([89b9aa8](https://github.com/vueblocks/element-schema-form/commit/89b9aa8b7cefbd81da8d08e6ae9d857d69809b6b)) 19 | 20 | ## [0.1.4](https://github.com/vueblocks/element-schema-form/compare/v0.1.3...v0.1.4) (2019-12-03) 21 | 22 | ### feat 23 | 24 | - 增加 timepicker 任意时间点选择 ([fcf5a3f](https://github.com/vueblocks/element-schema-form/commit/fcf5a3f3c1c275d7d1e02b0e25e2a7ac06638e6b)) 25 | 26 | ## [0.1.3](https://github.com/vueblocks/element-schema-form/compare/v0.1.2...v0.1.3) (2019-11-01) 27 | 28 | ### Bug Fixes 29 | 30 | - schema-form 插槽错误 ([fe43fbb](https://github.com/vueblocks/element-schema-form/commit/fe43fbb4c47984f092254536eff93c800617e6e7)) 31 | 32 | ## [0.1.2](https://github.com/vueblocks/element-schema-form/compare/v0.1.1...v0.1.2) (2019-10-30) 33 | 34 | ## [0.1.1](https://github.com/vueblocks/element-schema-form/compare/v0.1.0...v0.1.1) (2019-10-29) 35 | 36 | ### Features 37 | 38 | - 新增【重置表单】功能 ([9da36a3](https://github.com/vueblocks/element-schema-form/commit/9da36a37cadf06bedabf4bbdb9994ac620fa13e3)) 39 | 40 | ## [0.1.0](https://github.com/vueblocks/element-schema-form/compare/9c615890fe925a11c33f3b3534381332b9867cf7...v0.1.0) (2019-10-28) 41 | 42 | ### Bug Fixes 43 | 44 | - copy 激活行数调整,api 将 module 修改为 model ([d3682be](https://github.com/vueblocks/element-schema-form/commit/d3682be362dec1c3f96ee120fcebaf27664a75e4)) 45 | 46 | ### Features 47 | 48 | - 🌈 完成生成 Vue 代码功能 ([215dac0](https://github.com/vueblocks/element-schema-form/commit/215dac0ce0987f5e59b3507a51f5431da59af09e)) 49 | - 💥 引入 vuex-persistedstate 数据持久化插件 ([e825350](https://github.com/vueblocks/element-schema-form/commit/e825350561a37de53ecb78fa4d789bc7875ada5e)) 50 | - 📋 添加复制代码到剪切板功能 ([8e069b3](https://github.com/vueblocks/element-schema-form/commit/8e069b36113d7357705d30acf77b208b4a8d70b9)) 51 | - 修改布局算法 ([0d38a49](https://github.com/vueblocks/element-schema-form/commit/0d38a493503b80369276d6756de037571ea9847d)) 52 | - 基础组件 ([9c61589](https://github.com/vueblocks/element-schema-form/commit/9c615890fe925a11c33f3b3534381332b9867cf7)) 53 | - 增加 json 编辑器 ([3887414](https://github.com/vueblocks/element-schema-form/commit/38874147675504d40a670bacd4373dd109bc5f45)) 54 | - 增加列跨度配置 ([b6d72c6](https://github.com/vueblocks/element-schema-form/commit/b6d72c60720645b02076466f3bbd67e215934b3e)) 55 | - 增加拓展组件 ([d635fdd](https://github.com/vueblocks/element-schema-form/commit/d635fdd40349e93eecda0f52a9c249d2b87b0a6a)) 56 | - 增加组件个性化属性(1) ([2ca9dc7](https://github.com/vueblocks/element-schema-form/commit/2ca9dc74b296f6d0de97d6493245cde3aeca5afe)) 57 | - 增加组件基础属性编辑 ([30d335e](https://github.com/vueblocks/element-schema-form/commit/30d335ebede61056ca1c5c941d673a638c14429c)) 58 | - 增加表单预览 ([a70c222](https://github.com/vueblocks/element-schema-form/commit/a70c2222bc5358cd2e440299d0acd78032649599)) 59 | - 处理左侧布局删除列逻辑 ([c047010](https://github.com/vueblocks/element-schema-form/commit/c04701062e7eb8fbc2b59f66b8675cb15c172c5e)) 60 | - 完成生成 Schema 功能 ([dcbe5c5](https://github.com/vueblocks/element-schema-form/commit/dcbe5c51500a3f6b63985597b275d954a464ac3c)) 61 | - 搭建表单生成器页面 ([62d3085](https://github.com/vueblocks/element-schema-form/commit/62d30855341080e3de09b4291263fca3228cd5e5)) 62 | - 新增/删除行 ([f99ad57](https://github.com/vueblocks/element-schema-form/commit/f99ad57357db78ba3fc4f31aaee6a61e17d1a49b)) 63 | - 新增 tag 等基本组件 ([3e8c38d](https://github.com/vueblocks/element-schema-form/commit/3e8c38d56962faeb4e9f13a28f9af1fa9b8b863e)) 64 | - 新增列排序功能 ([0a74c03](https://github.com/vueblocks/element-schema-form/commit/0a74c03c62e4ada86d98127566a8cb5449cc324e)) 65 | - 新增行复制 ([6698e11](https://github.com/vueblocks/element-schema-form/commit/6698e11a3505fa884026ccfe981d543b82086cb4)) 66 | - 新增表单列删除功能 ([c08c8c0](https://github.com/vueblocks/element-schema-form/commit/c08c8c0c44bdb3ed76d9fce333992069cfb972d6)) 67 | - 新增表单配置面板 ([ecdbee5](https://github.com/vueblocks/element-schema-form/commit/ecdbee5557f6cddfe28617939f189d4f9de61992)) 68 | - 私有属性调整 ([cf61919](https://github.com/vueblocks/element-schema-form/commit/cf6191953e5117db4138d255dfd438022c03ddf5)) 69 | -------------------------------------------------------------------------------- /lib/demo.html: -------------------------------------------------------------------------------- 1 | 2 | element-schema-form demo 3 | 4 | 5 | 6 | 9 | -------------------------------------------------------------------------------- /lib/element-schema-form.umd.min.js: -------------------------------------------------------------------------------- 1 | (function(e,t){"object"===typeof exports&&"object"===typeof module?module.exports=t():"function"===typeof define&&define.amd?define([],t):"object"===typeof exports?exports["element-schema-form"]=t():e["element-schema-form"]=t()})("undefined"!==typeof self?self:this,(function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e["default"]}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s="fb15")}({"24fb":function(e,t,n){"use strict";function r(e,t){var n=e[1]||"",r=e[3];if(!r)return n;if(t&&"function"===typeof btoa){var a=o(r),i=r.sources.map((function(e){return"/*# sourceURL=".concat(r.sourceRoot).concat(e," */")}));return[n].concat(i).concat([a]).join("\n")}return[n].join("\n")}function o(e){var t=btoa(unescape(encodeURIComponent(JSON.stringify(e)))),n="sourceMappingURL=data:application/json;charset=utf-8;base64,".concat(t);return"/*# ".concat(n," */")}e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var n=r(t,e);return t[2]?"@media ".concat(t[2],"{").concat(n,"}"):n})).join("")},t.i=function(e,n){"string"===typeof e&&(e=[[null,e,""]]);for(var r={},o=0;on.parts.length&&(r.parts.length=n.parts.length)}else{var i=[];for(o=0;o-1}function Ge(e,t){var n=this.__data__,r=at(n,e);return r<0?n.push([e,t]):n[r][1]=t,this}function He(e){var t=-1,n=e?e.length:0;this.clear();while(++t-1&&e%1==0&&e-1&&e%1==0&&e<=a}function Wt(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function qt(e){return!!e&&"object"==typeof e}function Jt(e){return Bt(e)?rt(e):pt(e)}function Xt(){return[]}function Kt(){return!1}n.exports=Nt}).call(this,n("c8ba"),n("62e4")(e))},e6d7:function(e,t,n){"use strict";var r=n("581d"),o=n.n(r);o.a},f6fd:function(e,t){(function(e){var t="currentScript",n=e.getElementsByTagName("script");t in e||Object.defineProperty(e,t,{get:function(){try{throw new Error}catch(r){var e,t=(/.*at [^\(]*\((.*):.+:.+\)$/gi.exec(r.stack)||[!1])[1];for(e in n)if(n[e].src==t||"interactive"==n[e].readyState)return n[e];return null}}})})(document)},fad4:function(e,t,n){t=e.exports=n("24fb")(!1),t.push([e.i,".schema-form-tag .el-tag+.el-tag{margin-left:10px}.schema-form-tag .button-new-tag{margin-left:10px;height:32px;line-height:30px;padding-top:0;padding-bottom:0}.schema-form-tag .input-new-tag{width:90px;margin-left:10px;vertical-align:bottom}",""])},fb15:function(e,t,n){"use strict";var r;(n.r(t),"undefined"!==typeof window)&&(n("f6fd"),(r=window.document.currentScript)&&(r=r.src.match(/(.+\/)[^/]+\.js(\?.*)?$/))&&(n.p=r[1]));var o=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"schema-form"},e._l(e.formatedSchema,(function(t,r){return n("el-row",e._b({key:r,staticClass:"schema-form__row"},"el-row",e.layout,!1),[e._l(t,(function(t,r){return[t.hide?e._e():n("el-col",e._b({key:r},"el-col",t.colGrid,!1),[t.slot?e._t(t.slot):[n("schema-form-item",e._g(e._b({attrs:{prop:t.prop,col:t,model:e.model,options:e.options}},"schema-form-item",t.formItem,!1),e.$listeners),[t.labelSlot?e._t(t.labelSlot,null,{slot:t.labelSlot}):e._e(),t.frontSlot?e._t(t.frontSlot,null,{slot:t.frontSlot}):e._e(),t.rearSlot?e._t(t.rearSlot,null,{slot:t.rearSlot}):e._e()],2)]],2)]}))],2)})),1)},a=[],i=n("cd3f"),l=n.n(i),c={props:{layout:{type:Object,default(){return{}}},schema:{type:Array,required:!0,validator(e){return e.every(e=>Array.isArray(e)&&e.length>0)}},model:{type:Object,required:!0,default(){return{}}},options:{type:Object,default(){return{}}}},computed:{formatedSchema(){let e=l()(this.schema);return e.map(e=>{let t=e.filter(e=>!e.hide).length||1;e.map(e=>{e.colGrid=e.colGrid||{span:Math.round(24/t)}})}),e}}},s=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("el-form-item",e._b({staticClass:"schema-form-item",attrs:{prop:e.col.prop}},"el-form-item",e.col.formItem,!1),[e.col.labelSlot?n("template",{slot:"label"},[e._t(e.col.labelSlot)],2):e._e(),e.col.labelTooltip?n("template",{slot:"label"},[n("span",{staticClass:"schema-label"},[e._v(e._s(e.labelContent))]),n("el-tooltip",{attrs:{content:e.col.labelTooltip}},[n("i",{staticClass:"el-icon-warning"})])],1):e._e(),e.col.frontHtml?n("span",{domProps:{innerHTML:e._s(e.col.frontHtml)}}):e._e(),e.col.frontSlot?e._t(e.col.frontSlot):e._e(),n(e.getComponentName(e.col.type),e._g(e._b({tag:"component",attrs:{prop:e.col.prop,value:e.model[e.col.prop],modifier:e.col.modifier,dynamicAttrs:e.col.dynamicAttrs,onEvents:e.col.on,options:e.options[e.col.prop]},on:{"update:value":function(t){return e.$set(e.model,e.col.prop,t)}}},"component",e.col.attrs,!1),e.$listeners)),e.col.rearSlot?e._t(e.col.rearSlot):e._e(),e.col.rearHtml?n("span",{domProps:{innerHTML:e._s(e.col.rearHtml)}}):e._e()],2)},u=[],f={props:{model:{type:Object},options:{type:Object},col:{type:Object}},data(){return{builtInNames:["input","select","radio","datepicker","cascader","placeholder","checkbox","slider","timeselect","timepicker","jsoneditor","quill","codemirror","rate","switch","colorpicker","tags","progress"]}},computed:{labelContent(){let e=this.col.formItem||{};return e.label||""}},methods:{getComponentName(e){return this.builtInNames.includes(e)?"schema-form-"+e:e}}},p=f;n("c5ee");function d(e,t,n,r,o,a,i,l){var c,s="function"===typeof e?e.options:e;if(t&&(s.render=t,s.staticRenderFns=n,s._compiled=!0),r&&(s.functional=!0),a&&(s._scopeId="data-v-"+a),i?(c=function(e){e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,e||"undefined"===typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),o&&o.call(this,e),e&&e._registeredComponents&&e._registeredComponents.add(i)},s._ssrRegister=c):o&&(c=l?function(){o.call(this,this.$root.$options.shadowRoot)}:o),c)if(s.functional){s._injectStyles=c;var u=s.render;s.render=function(e,t){return c.call(t),u(e,t)}}else{var f=s.beforeCreate;s.beforeCreate=f?[].concat(f,c):[c]}return{exports:e,options:s}}var h=d(p,s,u,!1,null,"5fc0c8b5",null),m=h.exports,b={name:"SchemaForm",mixins:[c],components:{SchemaFormItem:m},mounted(){}},v=b,_=d(v,o,a,!1,null,null,null),g=_.exports,y=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("el-input",e._g(e._b({on:{change:function(t){return e.$emit("change",{prop:e.prop,value:t})}},model:{value:e.bindVal,callback:function(t){e.bindVal=t},expression:"bindVal"}},"el-input",e.attrsAll,!1),e.onEvents))},x=[],w={props:{value:[Number,String,Array,Object,Boolean,Date],prop:String,modifier:String,dynamicAttrs:Object,options:Array,onEvents:{type:Object,default(){return{}}}},computed:{bindVal:{get(){return this.formatVal(this.value)},set(e){this.$emit("update:value",this.formatVal(e))}},componentName(){let e=this.$options.name;return e.replace("SchemaForm","").toLowerCase()||""},globalOptions(){return this.$globalParams[this.componentName]||{}},attrsAll(){return{...this.globalOptions,...this.$attrs,...this.dynamicAttrs}}},methods:{formatVal(e){if("number"===this.modifier){let t=parseFloat(e);return isNaN(t)?e:t}return"trim"===this.modifier&&e?e.trim():e}}},S={name:"SchemaFormInput",mixins:[w]},j=S,A=d(j,y,x,!1,null,"0197489a",null),V=A.exports,$=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("el-select",e._g(e._b({on:{change:function(t){return e.$emit("change",{prop:e.prop,value:t})}},model:{value:e.bindVal,callback:function(t){e.bindVal=t},expression:"bindVal"}},"el-select",e.attrsAll,!1),e.onEvents),e._l(e.options,(function(t,r){return n("el-option",{key:t.value+"_"+r,attrs:{label:t.label,value:t.value,disabled:t.disabled}},[e.hasOptionSides?e._l(e.optionSides,(function(r,o){return n("span",{key:o,class:"side-"+o},[e._v(" "+e._s(t[r])+" ")])})):n("span",[e._v(e._s(t.label))])],2)})),1)},O=[],k={name:"SchemaFormSelect",mixins:[w],computed:{optionSides(){return this.attrsAll.optionSides||""},hasOptionSides(){return Array.isArray(this.optionSides)&&this.optionSides.length>=2}}},E=k,C=d(E,$,O,!1,null,"eb13bf92",null),F=C.exports,T=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("el-radio-group",e._g(e._b({on:{change:function(t){return e.$emit("change",{prop:e.prop,value:t})}},model:{value:e.bindVal,callback:function(t){e.bindVal=t},expression:"bindVal"}},"el-radio-group",e.attrsAll,!1),e.onEvents),e._l(e.options,(function(t,r){return n("el-radio",{key:t.value+"_"+r,attrs:{label:t.value,disabled:t.disabled}},[e._v(" "+e._s(t.label)+" ")])})),1)},I=[],P={name:"SchemaFormRadio",mixins:[w]},M=P,N=d(M,T,I,!1,null,"64ec35e0",null),R=N.exports,U=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("el-date-picker",e._g(e._b({on:{change:function(t){return e.$emit("change",{prop:e.prop,value:t})}},model:{value:e.bindVal,callback:function(t){e.bindVal=t},expression:"bindVal"}},"el-date-picker",e.attrsAll,!1),e.onEvents))},z=[],B={name:"SchemaFormDatepicker",mixins:[w]},L=B,D=d(L,U,z,!1,null,"3e551afa",null),G=D.exports,H=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("el-cascader",e._g(e._b({attrs:{options:e.options},on:{change:function(t){return e.$emit("change",{prop:e.prop,value:t})}},model:{value:e.bindVal,callback:function(t){e.bindVal=t},expression:"bindVal"}},"el-cascader",e.attrsAll,!1),e.onEvents))},W=[],q={name:"SchemaFormCascader",mixins:[w]},J=q,X=d(J,H,W,!1,null,"32fffb86",null),K=X.exports,Q=function(){var e=this,t=e.$createElement;e._self._c;return e._m(0)},Y=[function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"schema-form--placeholder"},[n("span",[e._v("Empty Field")])])}],Z={name:"SchemaFormPlaceholder"},ee=Z,te=d(ee,Q,Y,!1,null,"6c276bcc",null),ne=te.exports,re=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("el-checkbox-group",e._g(e._b({on:{change:function(t){return e.$emit("change",{prop:e.prop,value:t})}},model:{value:e.bindVal,callback:function(t){e.bindVal=t},expression:"bindVal"}},"el-checkbox-group",e.attrsAll,!1),e.onEvents),e._l(e.options,(function(t,r){return n("el-checkbox",{key:t.label+"_"+r,attrs:{label:t.value,disabled:t.disabled}},[e._v(e._s(t.label))])})),1)},oe=[],ae={name:"SchemaFormCheckbox",mixins:[w]},ie=ae,le=d(ie,re,oe,!1,null,"43dcbff7",null),ce=le.exports,se=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("el-slider",e._g(e._b({on:{change:function(t){return e.$emit("change",{prop:e.prop,value:t})}},model:{value:e.bindVal,callback:function(t){e.bindVal=t},expression:"bindVal"}},"el-slider",e.attrsAll,!1),e.onEvents))},ue=[],fe={name:"SchemaFormSlider",mixins:[w]},pe=fe,de=d(pe,se,ue,!1,null,"27c19576",null),he=de.exports,me=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("el-time-select",e._g(e._b({on:{change:function(t){return e.$emit("change",{prop:e.prop,value:t})}},model:{value:e.bindVal,callback:function(t){e.bindVal=t},expression:"bindVal"}},"el-time-select",e.attrsAll,!1),e.onEvents))},be=[],ve={name:"SchemaFormTimeselect",mixins:[w]},_e=ve,ge=d(_e,me,be,!1,null,"15a56bbc",null),ye=ge.exports,xe=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("el-time-picker",e._g(e._b({on:{change:function(t){return e.$emit("change",{prop:e.prop,value:t})}},model:{value:e.bindVal,callback:function(t){e.bindVal=t},expression:"bindVal"}},"el-time-picker",e.attrsAll,!1),e.onEvents))},we=[],Se={name:"SchemaFormTimepicker",mixins:[w]},je=Se,Ae=d(je,xe,we,!1,null,"2479ae50",null),Ve=Ae.exports,$e=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("el-rate",e._g(e._b({on:{change:function(t){return e.$emit("change",{prop:e.prop,value:t})}},model:{value:e.bindVal,callback:function(t){e.bindVal=t},expression:"bindVal"}},"el-rate",e.attrsAll,!1),e.onEvents))},Oe=[],ke={name:"SchemaFormRate",mixins:[w]},Ee=ke,Ce=d(Ee,$e,Oe,!1,null,"84ecef38",null),Fe=Ce.exports,Te=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("el-switch",e._g(e._b({on:{change:function(t){return e.$emit("change",{prop:e.prop,value:t})}},model:{value:e.bindVal,callback:function(t){e.bindVal=t},expression:"bindVal"}},"el-switch",e.attrsAll,!1),e.onEvents))},Ie=[],Pe={name:"SchemaFormSwitch",mixins:[w]},Me=Pe,Ne=d(Me,Te,Ie,!1,null,"46883290",null),Re=Ne.exports,Ue=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("el-color-picker",e._g(e._b({on:{change:function(t){return e.$emit("change",{prop:e.prop,value:t})}},model:{value:e.bindVal,callback:function(t){e.bindVal=t},expression:"bindVal"}},"el-color-picker",e.attrsAll,!1),e.onEvents))},ze=[],Be={name:"SchemaFormColorpicker",mixins:[w]},Le=Be,De=d(Le,Ue,ze,!1,null,"94550de0",null),Ge=De.exports,He=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"schema-form-tag"},[e._l(e.bindVal,(function(t,r){return n("el-tag",{key:t+"_"+r,attrs:{type:e.type,hit:e.hit,size:e.size,effect:e.effect,color:e.color,closable:e.closable,"disable-transitions":!1},on:{close:function(n){return e.handleClose(t)}}},[e._v(" "+e._s(t)+" ")])})),e.showAdd&&e.inputVisible?n("el-input",{ref:"saveTagInput",staticClass:"input-new-tag",attrs:{size:"small"},on:{blur:e.handleInputConfirm},nativeOn:{keyup:function(t){return!t.type.indexOf("key")&&e._k(t.keyCode,"enter",13,t.key,"Enter")?null:e.handleInputConfirm(t)}},model:{value:e.inputValue,callback:function(t){e.inputValue=t},expression:"inputValue"}}):e._e(),e.showAdd&&!e.inputVisible?n("el-button",{staticClass:"button-new-tag",attrs:{size:e.buttonSize,type:e.buttonType},on:{click:e.showInput}},[e._v(e._s(e.buttonWords))]):e._e()],2)},We=[],qe={computed:{showAdd(){return!!this.attrsAll["show-add"]&&this.attrsAll["show-add"]},closable(){return!this.attrsAll.hasOwnProperty("closable")||this.attrsAll.closable},type(){return this.attrsAll.type?this.attrsAll.type:""},hit(){return!!this.attrsAll.hit&&this.attrsAll.hit},size(){return this.attrsAll.size?this.attrsAll.size:""},effect(){return this.attrsAll.effect?this.attrsAll.effect:"light"},color(){return this.attrsAll.color?this.attrsAll.color:""},buttonSize(){return this.attrsAll["button-size"]?this.attrsAll["button-size"]:"small"},buttonWords(){return this.attrsAll["button-words"]?this.attrsAll["button-words"]:"+ New Tag"},buttonType(){return this.attrsAll["button-type"]?this.attrsAll["button-type"]:""}}},Je={name:"SchemaFormTags",mixins:[w,qe],data(){return{inputVisible:!1,inputValue:""}},methods:{handleClose(e){this.bindVal.splice(this.bindVal.indexOf(e),1),this.$emit("change",{prop:this.prop,value:this.bindVal})},showInput(){this.inputVisible=!0,this.$nextTick(e=>{this.$refs.saveTagInput.$refs.input.focus()})},handleInputConfirm(){let e=this.inputValue;e&&this.bindVal.push(e),this.inputVisible=!1,this.inputValue="",this.$emit("change",{prop:this.prop,value:this.bindVal})}}},Xe=Je,Ke=(n("e6d7"),d(Xe,He,We,!1,null,null,null)),Qe=Ke.exports,Ye=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("el-progress",e._g(e._b({attrs:{percentage:e.bindVal},on:{change:function(t){return e.$emit("change",{prop:e.prop,value:t})}}},"el-progress",e.attrsAll,!1),e.onEvents))},Ze=[],et={name:"SchemaFormProgress",mixins:[w]},tt=et,nt=d(tt,Ye,Ze,!1,null,"6c700e93",null),rt=nt.exports;const ot=[g,V,F,R,G,K,ne,ce,he,ye,Fe,Re,Ge,Qe,rt,Ve];function at(e,t={}){ot.forEach(t=>{e.component(t.name,t)}),e.prototype.$globalParams=t}var it=at;"undefined"!==typeof window&&window.Vue&&(window.Vue.use(at),at.installed&&(at.installed=!1)),n.d(t,"SchemaForm",(function(){return g})),n.d(t,"SchemaFormItem",(function(){return m})),n.d(t,"FormMixin",(function(){return w})),n.d(t,"LayoutMixin",(function(){return c}));t["default"]=it}})})); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@vueblocks/element-schema-form", 3 | "version": "0.1.8", 4 | "description": "A schema-based form generator component for Element UI.", 5 | "author": "xiaoluoboding ", 6 | "scripts": { 7 | "serve": "vue-cli-service serve", 8 | "build": "vue-cli-service build", 9 | "lint": "vue-cli-service lint", 10 | "build:lib": "vue-cli-service build --mode lib --target lib --name element-schema-form --dest lib src/index.js", 11 | "build:rollup": "rollup -c rollup.config.js", 12 | "build:demand": "cross-env MINIFY=true npm run build:rollup", 13 | "bundle": "npm run build:lib && npm run build:demand", 14 | "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0", 15 | "docs:build": "vuepress build docs", 16 | "docs:dev": "vuepress dev docs", 17 | "docs:deploy": "sh deploy.sh", 18 | "report": "vue-cli-service build --mode lib --target lib --name element-schema-form --dest lib --report src/index.js" 19 | }, 20 | "main": "lib/element-schema-form.umd.min.js", 21 | "unpkg": "lib/element-schema-form.umd.min.js", 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://github.com/vueblocks/element-schema-form.git" 25 | }, 26 | "keywords": [ 27 | "element", 28 | "json-schema", 29 | "form" 30 | ], 31 | "license": "MIT", 32 | "peerDependencies": { 33 | "element-ui": "^2.11.1" 34 | }, 35 | "dependencies": { 36 | "core-js": "^3.3.2", 37 | "vue": "^2.6.10" 38 | }, 39 | "devDependencies": { 40 | "@vue/cli-plugin-babel": "^4.0.5", 41 | "@vue/cli-plugin-eslint": "^4.0.5", 42 | "@vue/cli-service": "^4.0.5", 43 | "@vue/eslint-config-standard": "^4.0.0", 44 | "@vuepress/theme-default": "^1.8.2", 45 | "babel-eslint": "^10.0.1", 46 | "babel-plugin-component": "^1.1.1", 47 | "babel-plugin-lodash": "^3.3.4", 48 | "babel-plugin-transform-remove-console": "^6.9.4", 49 | "cross-env": "^6.0.3", 50 | "element-theme-chalk": "^2.10.1", 51 | "element-ui": "^2.11.1", 52 | "eslint": "^5.16.0", 53 | "eslint-plugin-vue": "^5.0.0", 54 | "jsoneditor": "^7.0.1", 55 | "less": "^3.0.4", 56 | "less-loader": "^4.1.0", 57 | "lodash.clonedeep": "^4.5.0", 58 | "lodash.isequal": "^4.5.0", 59 | "normalize.css": "^8.0.1", 60 | "rollup-plugin-babel": "^4.3.3", 61 | "rollup-plugin-commonjs": "^10.1.0", 62 | "rollup-plugin-filesize": "^6.2.1", 63 | "rollup-plugin-json": "^4.0.0", 64 | "rollup-plugin-node-resolve": "^5.2.0", 65 | "rollup-plugin-terser": "^5.1.2", 66 | "rollup-plugin-vue": "^5.1.0", 67 | "terser": "^4.3.9", 68 | "vue-codemirror-lite": "^1.0.4", 69 | "vue-router": "^3.0.3", 70 | "vue-template-compiler": "^2.6.10", 71 | "vue2-editor": "^2.10.2", 72 | "vuepress": "^0.14.5", 73 | "vuex": "^3.0.1" 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vueblocks/element-schema-form/ff2a3ae205d3034d0dd38ab666c68eb2171cc2de/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | element-schema-form 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel' 2 | import cjs from 'rollup-plugin-commonjs' 3 | import filesize from 'rollup-plugin-filesize' 4 | import json from 'rollup-plugin-json' 5 | import node from 'rollup-plugin-node-resolve' 6 | import vue from 'rollup-plugin-vue' 7 | import { terser } from 'rollup-plugin-terser' 8 | 9 | const components = require('./src/components') 10 | 11 | const isMinify = !!process.env.MINIFY 12 | 13 | const plugins = [ 14 | babel({ 15 | runtimeHelpers: true, 16 | exclude : 'node_modules/**' 17 | }), 18 | cjs({ 19 | sourceMap: false 20 | }), 21 | filesize(), 22 | json(), 23 | node(), 24 | vue() 25 | ] 26 | 27 | if (isMinify) { 28 | plugins.push(terser({ 29 | compress: { 30 | drop_console: true 31 | } 32 | })) 33 | } 34 | 35 | const buildOutput = fileName => { 36 | return [ 37 | { 38 | file: isMinify 39 | ? `./lib/${fileName}.common.min.js` 40 | : `./lib/${fileName}.common.js`, 41 | format: 'cjs', 42 | sourcemap: false, 43 | exports: 'named', 44 | globals: { 45 | 'vue-codemirror-lite': 'vueCodemirrorLite', 46 | 'vue2-editor': 'vue2Editor' 47 | } 48 | }, 49 | { 50 | file: isMinify 51 | ? `./lib/${fileName}.umd.min.js` 52 | : `./lib/${fileName}.umd.js`, 53 | format: 'umd', 54 | name: fileName, 55 | sourcemap: false, 56 | globals: { 57 | 'vue-codemirror-lite': 'vueCodemirrorLite', 58 | 'vue2-editor': 'vue2Editor' 59 | } 60 | } 61 | ] 62 | } 63 | 64 | const buildOptions = components => { 65 | return Object.keys(components).map(key => { 66 | return { 67 | input: components[key], 68 | output: buildOutput(key), 69 | plugins, 70 | external: [ 71 | 'vueCodemirrorLite', 72 | 'vue2Editor' 73 | ] 74 | } 75 | }) 76 | } 77 | 78 | 79 | export default buildOptions(components) 80 | -------------------------------------------------------------------------------- /src/components.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'SchemaFormCodemirror': './src/packages/components/schema-form-codemirror/index.js', 3 | 'SchemaFormQuill': './src/packages/components/schema-form-quill/index.js' 4 | // 'SchemaFormJsoneditor': './src/packages/components/schema-form-jsoneditor/index.js' 5 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import SchemaForm from './packages/SchemaForm.vue' 2 | import SchemaFormInput from './packages/components/SchemaFormInput.vue' 3 | import SchemaFormSelect from './packages/components/SchemaFormSelect.vue' 4 | import SchemaFormRadio from './packages/components/SchemaFormRadio.vue' 5 | import SchemaFormDatepicker from './packages/components/SchemaFormDatepicker.vue' 6 | import SchemaFormCascader from './packages/components/SchemaFormCascader.vue' 7 | import SchemaFormPlaceholder from './packages/components/SchemaFormPlaceholder.vue' 8 | import SchemaFormCheckbox from './packages/components/SchemaFormCheckbox.vue' 9 | import SchemaFormSlider from './packages/components/SchemaFormSlider.vue' 10 | import SchemaFormTimeselect from './packages/components/SchemaFormTimeselect.vue' 11 | import SchemaFormTimepicker from './packages/components/SchemaFormTimepicker.vue' 12 | import SchemaFormRate from './packages/components/SchemaFormRate.vue' 13 | import SchemaFormSwitch from './packages/components/SchemaFormSwitch.vue' 14 | import SchemaFormColorpicker from './packages/components/SchemaFormColorpicker.vue' 15 | import SchemaFormTags from './packages/components/SchemaFormTags.vue' 16 | import SchemaFormProgress from './packages/components/SchemaFormProgress.vue' 17 | 18 | import SchemaFormItem from './packages/SchemaFormItem.vue' 19 | 20 | import FormMixin from './packages/mixins/form-mixin' 21 | import LayoutMixin from './packages/mixins/layout-mixin' 22 | 23 | const components = [ 24 | SchemaForm, 25 | SchemaFormInput, 26 | SchemaFormSelect, 27 | SchemaFormRadio, 28 | SchemaFormDatepicker, 29 | SchemaFormCascader, 30 | SchemaFormPlaceholder, 31 | SchemaFormCheckbox, 32 | SchemaFormSlider, 33 | SchemaFormTimeselect, 34 | SchemaFormRate, 35 | SchemaFormSwitch, 36 | SchemaFormColorpicker, 37 | SchemaFormTags, 38 | SchemaFormProgress, 39 | SchemaFormTimepicker 40 | ] 41 | 42 | function install (Vue, opts = {}) { 43 | components.forEach(component => { 44 | Vue.component(component.name, component) 45 | }) 46 | Vue.prototype.$globalParams = opts 47 | } 48 | 49 | export default install 50 | 51 | export { 52 | SchemaForm, 53 | SchemaFormItem, 54 | FormMixin, 55 | LayoutMixin 56 | } 57 | 58 | if (typeof window !== 'undefined' && window.Vue) { 59 | window.Vue.use(install) 60 | if (install.installed) { 61 | install.installed = false 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/packages/SchemaForm.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 48 | 49 | 52 | -------------------------------------------------------------------------------- /src/packages/SchemaFormItem.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 71 | 72 | 88 | -------------------------------------------------------------------------------- /src/packages/components/SchemaFormCascader.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 20 | 21 | 24 | -------------------------------------------------------------------------------- /src/packages/components/SchemaFormCheckbox.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 25 | 26 | 29 | -------------------------------------------------------------------------------- /src/packages/components/SchemaFormColorpicker.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /src/packages/components/SchemaFormDatepicker.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 19 | 20 | 23 | -------------------------------------------------------------------------------- /src/packages/components/SchemaFormInput.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 19 | 20 | 23 | -------------------------------------------------------------------------------- /src/packages/components/SchemaFormPlaceholder.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /src/packages/components/SchemaFormProgress.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /src/packages/components/SchemaFormRadio.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 27 | 28 | 31 | -------------------------------------------------------------------------------- /src/packages/components/SchemaFormRate.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /src/packages/components/SchemaFormSelect.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 41 | 42 | 45 | -------------------------------------------------------------------------------- /src/packages/components/SchemaFormSlider.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /src/packages/components/SchemaFormSwitch.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /src/packages/components/SchemaFormTags.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 72 | 73 | 93 | -------------------------------------------------------------------------------- /src/packages/components/SchemaFormTimepicker.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 19 | 20 | 23 | -------------------------------------------------------------------------------- /src/packages/components/SchemaFormTimeselect.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 19 | 20 | 23 | -------------------------------------------------------------------------------- /src/packages/components/schema-form-codemirror/SchemaFormCodemirror.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 25 | 26 | 29 | -------------------------------------------------------------------------------- /src/packages/components/schema-form-codemirror/index.js: -------------------------------------------------------------------------------- 1 | import SchemaFormCodemirror from './SchemaFormCodemirror.vue' 2 | 3 | SchemaFormCodemirror.install = function (Vue) { 4 | Vue.component(SchemaFormCodemirror.name, SchemaFormCodemirror) 5 | } 6 | 7 | export default SchemaFormCodemirror 8 | -------------------------------------------------------------------------------- /src/packages/components/schema-form-jsoneditor/SchemaFormJsoneditor.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 65 | 66 | 69 | -------------------------------------------------------------------------------- /src/packages/components/schema-form-jsoneditor/index.js: -------------------------------------------------------------------------------- 1 | import SchemaFormJsoneditor from './SchemaFormJsoneditor.vue' 2 | 3 | SchemaFormJsoneditor.install = function (Vue) { 4 | Vue.component(SchemaFormJsoneditor.name, SchemaFormJsoneditor) 5 | } 6 | 7 | export default SchemaFormJsoneditor 8 | -------------------------------------------------------------------------------- /src/packages/components/schema-form-quill/SchemaFormQuill.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 23 | 24 | 27 | -------------------------------------------------------------------------------- /src/packages/components/schema-form-quill/index.js: -------------------------------------------------------------------------------- 1 | import SchemaFormQuill from './SchemaFormQuill.vue' 2 | 3 | SchemaFormQuill.install = function (Vue) { 4 | Vue.component(SchemaFormQuill.name, SchemaFormQuill) 5 | } 6 | 7 | export default SchemaFormQuill 8 | -------------------------------------------------------------------------------- /src/packages/mixins/form-code-mirror-mixin.js: -------------------------------------------------------------------------------- 1 | export default { 2 | computed: { 3 | cmOptions () { // codeMirror 配置项 详见 https://codemirror.net/doc/manual.html#config 4 | return this.attrsAll.cmOptions ? this.attrsAll.cmOptions : { 5 | tabSize: 2, 6 | lineNumbers: true, 7 | line: true 8 | } 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/packages/mixins/form-json-editor-mixin.js: -------------------------------------------------------------------------------- 1 | export default { 2 | computed: { 3 | width () { // 编辑器宽 4 | return this.attrsAll.width ? this.attrsAll.width : '100%' 5 | }, 6 | height () { // 编辑器高 7 | return this.attrsAll.width ? this.attrsAll.width : '400px' 8 | }, 9 | mode () { // 编辑器模式 10 | return this.attrsAll.mode ? this.attrsAll.mode : 'code' 11 | }, 12 | editorOptions () { // 配置项 13 | return this.attrsAll.options ? this.attrsAll.options : {} 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/packages/mixins/form-mixin.js: -------------------------------------------------------------------------------- 1 | export default { 2 | props: { 3 | value: [Number, String, Array, Object, Boolean, Date], // 绑定值 4 | prop: String, 5 | modifier: String, // v-model修饰符 6 | dynamicAttrs: Object, // 动态属性 7 | options: Array, // 多选项目 8 | onEvents: { // 绑定事件 9 | type: Object, 10 | default () { return {} } 11 | } 12 | }, 13 | computed: { 14 | bindVal: { 15 | get () { 16 | return this.formatVal(this.value) 17 | }, 18 | set (val) { 19 | this.$emit('update:value', this.formatVal(val)) 20 | } 21 | }, 22 | componentName () { 23 | let _name = this.$options.name 24 | return _name.replace('SchemaForm', '').toLowerCase() || '' 25 | }, 26 | globalOptions () { 27 | return this.$globalParams[this.componentName] || {} 28 | }, 29 | attrsAll () { 30 | return { ...this.globalOptions, ...this.$attrs, ...this.dynamicAttrs } 31 | } 32 | }, 33 | methods: { 34 | formatVal (val) { 35 | if (this.modifier === 'number') { 36 | let n = parseFloat(val) 37 | return isNaN(n) ? val : n 38 | } 39 | if (this.modifier === 'trim' && val) return val.trim() 40 | return val 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/packages/mixins/form-tags-mixin.js: -------------------------------------------------------------------------------- 1 | export default { 2 | computed: { 3 | showAdd () { // 是否展示新增按钮 4 | return this.attrsAll['show-add'] ? this.attrsAll['show-add'] : false 5 | }, 6 | closable () { // 标签是否可删除 7 | return this.attrsAll.hasOwnProperty('closable') ? this.attrsAll.closable : true 8 | }, 9 | type () { // 标签类型 10 | return this.attrsAll.type ? this.attrsAll.type : '' 11 | }, 12 | hit () { // 标签是否有边框描边 13 | return this.attrsAll.hit ? this.attrsAll.hit : false 14 | }, 15 | size () { // 标签尺寸 16 | return this.attrsAll.size ? this.attrsAll.size : '' 17 | }, 18 | effect () { // 标签主题 19 | return this.attrsAll.effect ? this.attrsAll.effect : 'light' 20 | }, 21 | color () { // 标签背景色 22 | return this.attrsAll.color ? this.attrsAll.color : '' 23 | }, 24 | buttonSize () { // 按钮尺寸 25 | return this.attrsAll['button-size'] ? this.attrsAll['button-size'] : 'small' 26 | }, 27 | buttonWords () { // 按钮文案 28 | return this.attrsAll['button-words'] ? this.attrsAll['button-words'] : '+ New Tag' 29 | }, 30 | buttonType () { // 按钮类型 31 | return this.attrsAll['button-type'] ? this.attrsAll['button-type'] : '' 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/packages/mixins/layout-mixin.js: -------------------------------------------------------------------------------- 1 | import cloneDeep from 'lodash.clonedeep' 2 | 3 | export default { 4 | props: { 5 | layout: { // 关于el-row 的拓展 6 | type: Object, 7 | default () { return {} } 8 | }, 9 | schema: { // 表单的格局 10 | type: Array, 11 | required: true, 12 | validator (val) { 13 | return val.every(arr => Array.isArray(arr) && arr.length > 0) 14 | } 15 | }, 16 | model: { // 绑定的value值 17 | type: Object, 18 | required: true, 19 | default () { return {} } 20 | }, 21 | options: { // 多选值绑定的陪选项目 22 | type: Object, 23 | default () { return {} } 24 | } 25 | }, 26 | computed: { 27 | formatedSchema () { 28 | let _schema = cloneDeep(this.schema) 29 | _schema.map(list => { 30 | let _showNum = list.filter(item => !item.hide).length || 1 31 | list.map(obj => { obj.colGrid = obj.colGrid || { span: Math.round(24 / _showNum) } }) 32 | }) 33 | return _schema 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | const isProd = process.env.NODE_ENV === 'production' 4 | const isLib = process.env.VUE_APP_BUILD_MODE === 'lib' 5 | const resolve = dir => path.join(__dirname, dir) 6 | 7 | const setChainWebpack = config => { 8 | // 修改默认目录简写 9 | config.resolve.alias 10 | .set('@', path.resolve('app')) 11 | // 添加对 app 目录的支持 12 | config.module 13 | .rule('js') 14 | .include 15 | .add('/app') 16 | .end() 17 | .use('babel') 18 | .loader('babel-loader') 19 | if (isProd) { 20 | /** 21 | * 清除性能警告 22 | * entrypoint size limit (244 KiB) 23 | * asset size limit (244 KiB) 24 | */ 25 | config.performance 26 | .set('maxEntrypointSize', 2500000) 27 | .set('maxAssetSize', 2000000) 28 | // drop console 29 | config.optimization.minimizer('terser').tap((args) => { 30 | args[0].terserOptions.compress.drop_console = true 31 | return args 32 | }) 33 | } 34 | } 35 | 36 | const setConfigureWebpack = config => { 37 | const externalLibs = [ 38 | 'vue', 39 | 'codemirror', 40 | 'jsoneditor', 41 | 'vue-codemirror-lite', 42 | 'vue2-editor' 43 | ] 44 | // 将 vue 设置为外部依赖 45 | let externals = [ 46 | function (context, request, callback) { 47 | for (const lib of externalLibs) { 48 | const reg = new RegExp(`^${lib}`) 49 | if (reg.test(request)) { 50 | return callback(null, lib) 51 | } 52 | } 53 | callback() 54 | } 55 | ] 56 | return isLib ? { 57 | externals 58 | } : {} 59 | } 60 | 61 | module.exports = { 62 | publicPath: './', 63 | pages: { 64 | index: { 65 | entry: resolve('app/main.js') // 修改默认打包文件入口 66 | } 67 | }, 68 | lintOnSave: true, 69 | productionSourceMap: false, 70 | chainWebpack: config => setChainWebpack(config), 71 | configureWebpack: config => setConfigureWebpack(config), 72 | css: { 73 | extract: false 74 | }, 75 | devServer: { 76 | port: 4545, 77 | open: true, 78 | overlay: { 79 | warnings: true, 80 | errors: true 81 | } 82 | } 83 | } 84 | --------------------------------------------------------------------------------