Vue3 component (IX) Vue + element plus + JSON = dynamic rendering form control component

itread01 2021-02-23 00:37:43
vue3 vue component ix vue


# A mature form , You've grown up , You have to learn :* Dynamic rendering * Support single column 、 Diallel 、 Multiple columns * Support to adjust the layout * Support form validation * Support to adjust the arrangement ( Display ) Sequence * Display the required component according to the component value * Support item Expansion kit components * Can automatically create model> This form control component is based on **element-plus** Of el-form The second package we did , So first of all, thank you element-plus Provides such a powerful UI Ku , Previously used jQuery I've done something like that , But it's very troublesome , It doesn't look good , Maintainability 、 Expansion kits are also poor , A lot of ideas don't come true ( Technology is limited ). Now it's all right , Standing on the shoulders of giants , I realized my idea .# To achieve dynamic rendering, the form needs properties , Put it all in json Inside , And then use require( convenient ) perhaps aioxs( Can be hot updated ) Load in , In this way, dynamic rendering can be realized . For example, to add company information 、 modify , Then you just need to load the company information json that will do . Want to add employee information 、 modify , Then you just need to load the employee information json.** All in all , Load the required json that will do , There's no need to hand code over and over again .** So this amazing json What does it look like ? The file is a little long , Look directly at the screenshot , More clearly .![006 What dynamic rendering needs json.png](https://upload-images.jianshu.io/upload_images/25078225-144343abdf034cdb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) There are several additional features :* Support merging under single line . In the case of a single line , Some short control elements will take up more space , We can merge multiple small ones into one line .* Support expansion kits under multiple lines . In the case of multiple lines , Some long control elements need to take up more space , We can set it to take up a few more squares .* What you need to create a form automatically model. You don't have to write it manually model 了 .# Realize the form of multi row and multi column. Thank you again el-form, It's really powerful , It's not just beautiful , Verification function is also provided , There are many other features . It's just like it can only be arranged horizontally , Or standing up . So can we have more rows and more columns ? There seems to be no direct provision of . We know el-row、el-col It can realize the function of multi row and multi column , So can we combine them ? The official website doesn't say it directly , I'm looking for , Fortunately, I found .( ok , In fact, after a while table) Just combine the two , Here's a little trick ,el-row Just one is enough ,el-col There can be multiple , When this line is full , It will automatically go to the next line .```js ```* formColSort Store components ID Array of , It determines which components are displayed and the order in which they are displayed .* v-for Traversal formColSort Get the components ID, And get ID Corresponding span( Determine the occupancy ) And what components need meta.* formColSpan An array of storage elements . According to el-col Of span Of 24 Grid settings .* getCtrMeta(ctrId) According to the components ID Get the meta. Why write a function ? Because model Parentheses are not allowed for properties of , So I have to write a function . Why not compute properties ? Calculating properties doesn't seem to pass arguments .* component :is="xxx" Vue Dynamic components provided , You can easily load different types of sub components with this .* ctlList Component Dictionary , Change the component type to the corresponding component label .> Such a v-for A lot of things have been done , For example, single column 、 Multiple columns , The scheduling problem of components , The space occupying problem of components , There is also the problem of displaying different components according to the user's choice , In fact, it's just a revision formColSort The components in the system ID The composition and order of the .# Automatic creation model I'm lazy , Hand rolling model Isn't it a bit troublesome ? If only we could get it automatically , So I wrote this function .```js // According to the form elements meta, establish v-model const createModel = () => { // According to meta, establish module for (const key in formItemMeta) { const m = formItemMeta[key] // Set the property value according to the control component type switch (m.controlType) { case 100: // Words case 101: case 102: case 103: case 104: case 105: case 106: case 107: case 130: case 131: formModel[m.colName] = '' break case 110: // date case 111: // Date time case 112: // years case 114: // year case 113: // Year week formModel[m.colName] = null break case 115: // At any time formModel[m.colName] = '00:00:00' break case 116: // Choose the time formModel[m.colName] = '00:00' break case 120: // Numbers case 121: formModel[m.colName] = 0 break case 150: // Tick case 151: // Switch formModel[m.colName] = false break case 153: // Single choice group case 160: // Pull down the radio case 162: // Pull down linkage formModel[m.colName] = null break case 152: // Multiple choice group case 161: // Pull down multiple choices formModel[m.colName] = [] break } // See if there's a default set if (typeof m.defaultValue !== 'undefined') { switch (m.defaultValue) { case '': break case '{}': formModel[m.colName] = {} break case '[]': formModel[m.colName] = [] break case 'date': formModel[m.colName] = new Date() break default: formModel[m.colName] = m.defaultValue break } } } // Synchronization of the parent component v-model context.emit('update:modelValue', formModel) return formModel }``` Depending on the type and default values , Set model Attribute , It's much more convenient .# Create user selected model The user selects an option , The components of the form respond to the changed model. I need such a simple one in my plan model, So I wrote another function ```js // Depending on user options , Set up the corresponding model const createPartModel = (array) => { // Delete attributes first for (const key in formPartModel) { delete formPartModel[key] } // Create new attributes for (let i = 0; i < array.length; i++) { const colName = formItemMeta[array[i]].colName formPartModel[colName] = formModel[colName] } }``` So you can get a simple model 了 .# Multi column form, this is the most complex , There are two situations : Single row squeeze 、 Multi column position grabbing .## Single column ![007 Single column form .png](https://upload-images.jianshu.io/upload_images/25078225-6b11f46b11eee46e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) A single column form has one feature , The line is relatively loose , So sometimes you need to display two components in one line , The others are one component per line , So how to adjust ? Here's a setup :* One component, one line , Remember to do 1* Two components in a row , Remember to do -2* Three components in a row , Remember to do -3 And so on , In theory, the most support is -24, Of course, it doesn't seem to have such a wide display . After recording like this , We can judge ,≥1 Remember to do span=24, Negative , use 24 Remove , What you get is span The number of . Of course, take the whole number . Why mark it with a negative number ? It's just to distinguish the adjustment of multiple columns .## Multiple columns ![008 Double column form .png](https://upload-images.jianshu.io/upload_images/25078225-60ce0f9770bf5732.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) * I found a problem after adjusting too much , It looks the same as after single column adjustment .*![009 Three column form .png](https://upload-images.jianshu.io/upload_images/25078225-fc0a55bcdaf2edc5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) A multi column form has one feature , One grid is smaller , Some components are too long to fit , At this time, this component will be used in the back grid . So let's make a setting :* One element occupies one grid , Still remember to do 1* One element occupies two cells , Remember to do 2* One element occupies three spaces , Remember to do 3 And so on . After recording like this , We can judge ,≤1 Of , Remember to do 24 / Number of columns , Bigger than 1 Remember to do 24/ Number of columns * n. That's it , Can be compatible with single column settings , There is no need to adjust the settings because of changing from single column to multi column . Just a little trouble , If it takes up too much space , It will be squeezed to the next line , And there will be “ vacancy ”. Let's adjust this manually for the time being . After all, which field is in the front , It needs to be set manually . An analysis is as fierce as a tiger , There are few lines of code .```js // According to the configuration colCount, Set formColSpan const setFormColSpan = () => { const formColCount = formMeta.formColCount // Number of columns const moreColSpan = 24 / formColCount // How many copies of a grid if (formColCount === 1) { // A column of information for (const key in formItemMeta) { const m = formItemMeta[key] if (typeof m.colCount === 'undefined') { formColSpan[m.controlId] = moreColSpan } else { if (m.colCount >= 1) { // Single column , Only 24 grid formColSpan[m.controlId] = moreColSpan } else if (m.colCount < 0) { // A squeeze situation , 24 Divide Share of formColSpan[m.controlId] = moreColSpan / (0 - m.colCount) } } } } else { // In the case of multiple columns for (const key in formItemMeta) { const m = formItemMeta[key] if (typeof m.colCount === 'undefined') { formColSpan[m.controlId] = moreColSpan } else { if (m.colCount < 0 || m.colCount === 1) { // Multiple columns , Squeeze a share of formColSpan[m.controlId] = moreColSpan } else if (m.colCount > 1) { // Multiple columns , The number of squares occupied * Number of copies formColSpan[m.controlId] = moreColSpan * m.colCount } } } } }``` Finally, let's see the effect , The number of columns can be set dynamically : 【 Video one 】[https://www.zhihu.com/zvideo/1347091197660405760](https://www.zhihu.com/zvideo/1347091197660405760)# According to the user's choice , Displaying the corresponding components is also an urgent function , Otherwise , The adaptability of dynamic rendering form control components will be limited . Actually, it's not hard to think about it , Just change it formColSort The components inside ID Just fine . Let's set one watch To monitor changes in component values , And then put the components you need ID Set to formColSort That's all right. .```js // Monitor changes in component values , Adjust the display of components and display order if (typeof formMeta.formColShow !== 'undefined') { for (const key in formMeta.formColShow) { const ctl = formMeta.formColShow[key] const colName = formItemMeta[key].colName watch(() => formModel[colName], (v1, v2) => { if (typeof ctl[v1] === 'undefined') { // No settings , Display preset components setFormColSort() } else { // According to the setting, the display element setFormColSort(ctl[v1]) // Set part of model createPartModel(ctl[v1]) } }) } }``` Because there may be more than one component to monitor , So I did a loop , So you can listen to all the components you need . Look at the effect 【 Video 2 】[https://www.zhihu.com/zvideo/1347099700483457024](https://www.zhihu.com/zvideo/1347099700483457024)# The code above the complete code is messy , Here's a general introduction .* el-form-manage.js Management class of form component , Take it out alone , So that we can support other UI It's in storage , such as antdv```jsimport { reactive, watch } from 'vue'/** * Form management class * * establish v-model * * Adjust the number of columns * * Merge */const formManage = (props, context) => { // Define complete v-model const formModel = reactive({}) // Define regional model const formPartModel = reactive({}) // Determine how many cells a component occupies const formColSpan = reactive({}) // Define sort by const formColSort = reactive([]) // Get the form meta const formMeta = props.meta console.log('formMeta', formMeta) // Form elements meta const formItemMeta = formMeta.itemMeta // Form validation meta, Reserve // const formRuleMeta = formMeta.ruleMeta // According to the form elements meta, establish v-model const createModel = () => { // According to meta, establish module for (const key in formItemMeta) { const m = formItemMeta[key] // Set the property value according to the control component type switch (m.controlType) { case 100: // Words case 101: case 102: case 103: case 104: case 105: case 106: case 107: case 130: case 131: formModel[m.colName] = '' break case 110: // date case 111: // Date time case 112: // years case 114: // year case 113: // Year week formModel[m.colName] = null break case 115: // At any time formModel[m.colName] = '00:00:00' break case 116: // Choose the time formModel[m.colName] = '00:00' break case 120: // Numbers case 121: formModel[m.colName] = 0 break case 150: // Tick case 151: // Switch formModel[m.colName] = false break case 153: // Single choice group case 160: // Pull down the radio case 162: // Pull down linkage formModel[m.colName] = null break case 152: // Multiple choice group case 161: // Pull down multiple choices formModel[m.colName] = [] break } // See if there's a default set if (typeof m.defaultValue !== 'undefined') { switch (m.defaultValue) { case '': break case '{}': formModel[m.colName] = {} break case '[]': formModel[m.colName] = [] break case 'date': formModel[m.colName] = new Date() break default: formModel[m.colName] = m.defaultValue break } } } // Synchronization of the parent component v-model context.emit('update:modelValue', formModel) return formModel } // Do it one time first createModel() // Submit... To the parent component model const mySubmit = (val, controlId, colName) => { context.emit('update:modelValue', formModel) // Sync to part model if (typeof formPartModel[colName] !== 'undefined') { formPartModel[colName] = formModel[colName] } context.emit('update:partModel', formPartModel) } // Depending on user options , Set up the corresponding model const createPartModel = (array) => { // Delete attributes first for (const key in formPartModel) { delete formPartModel[key] } // Create new attributes for (let i = 0; i < array.length; i++) { const colName = formItemMeta[array[i]].colName formPartModel[colName] = formModel[colName] } } // According to the configuration colCount, Set formColSpan const setFormColSpan = () => { const formColCount = formMeta.formColCount // Number of columns const moreColSpan = 24 / formColCount // How many copies of a grid if (formColCount === 1) { // A column of information for (const key in formItemMeta) { const m = formItemMeta[key] if (typeof m.colCount === 'undefined') { formColSpan[m.controlId] = moreColSpan } else { if (m.colCount >= 1) { // Single column , Only 24 grid formColSpan[m.controlId] = moreColSpan } else if (m.colCount < 0) { // A squeeze situation , 24 Divide Share of formColSpan[m.controlId] = moreColSpan / (0 - m.colCount) } } } } else { // In the case of multiple columns for (const key in formItemMeta) { const m = formItemMeta[key] if (typeof m.colCount === 'undefined') { formColSpan[m.controlId] = moreColSpan } else { if (m.colCount < 0 || m.colCount === 1) { // Multiple columns , Squeeze a share of formColSpan[m.controlId] = moreColSpan } else if (m.colCount > 1) { // Multiple columns , The number of squares occupied * Number of copies formColSpan[m.controlId] = moreColSpan * m.colCount } } } } } // Do it one time first setFormColSpan() // Set the display order of components const setFormColSort = (array = formMeta.colOrder) => { formColSort.length = 0 formColSort.push(...array) } // Do it first setFormColSort() // Monitor changes in component values , Adjust the display of components and display order if (typeof formMeta.formColShow !== 'undefined') { for (const key in formMeta.formColShow) { const ctl = formMeta.formColShow[key] const colName = formItemMeta[key].colName watch(() => formModel[colName], (v1, v2) => { if (typeof ctl[v1] === 'undefined') { // No settings , Display preset components setFormColSort() } else { // According to the setting, the display element setFormColSort(ctl[v1]) // Set part of model createPartModel(ctl[v1]) } }) } } return { // thing formModel, // v-model createModel() formPartModel, // Of the components selected by the user model formColSpan, // Determine the component occupancy formColSort, // Determine component sequencing // Function createModel, // establish v-model setFormColSpan, // Set the element occupancy setFormColSort, // Set component sequencing mySubmit // Submit }}export default formManage```* el-form-map.js Dynamic components need dictionaries ```jsimport { defineAsyncComponent } from 'vue'/** * Register control components in components * * written words * ** eltext Single line text 、 Telephone 、 Mail 、 Search for * ** elarea Multiline text * ** elurl * * Numbers * ** elnumber Numbers * ** elrange Slider * * date * ** eldate date 、 years 、 Year week 、 year * ** eltime Time * * Choice * ** elcheckbox Tick * ** elswitch Switch * ** elcheckboxs Multiple choice group * ** elradios Single choice group * ** elselect Drop down to select */const formItemList = { // Words defineComponent eltext: defineAsyncComponent(() => import('./t-text.vue')), elarea: defineAsyncComponent(() => import('./t-area.vue')), elurl: defineAsyncComponent(() => import('./t-url.vue')), // Numbers elnumber: defineAsyncComponent(() => import('./n-number.vue')), elrange: defineAsyncComponent(() => import('./n-range.vue')), // date 、 Time eldate: defineAsyncComponent(() => import('./d-date.vue')), eltime: defineAsyncComponent(() => import('./d-time.vue')), // Choice 、 Switch elcheckbox: defineAsyncComponent(() => import('./s-checkbox.vue')), elswitch: defineAsyncComponent(() => import('./s-switch.vue')), elcheckboxs: defineAsyncComponent(() => import('./s-checkboxs.vue')), elradios: defineAsyncComponent(() => import('./s-radios.vue')), elselect: defineAsyncComponent(() => import('./s-select.vue')), elselwrite: defineAsyncComponent(() => import('./s-selwrite.vue'))}/** * A dictionary of dynamic components , So v-for Set the control elements in the loop */const formItemListKey = { // Words 100: formItemList.elarea, // Multiline text 101: formItemList.eltext, // Single line text 102: formItemList.eltext, // code 103: formItemList.eltext, // Telephone 104: formItemList.eltext, // Mail 105: formItemList.elurl, // url 106: formItemList.eltext, // Search for // Numbers 120: formItemList.elnumber, // Array 121: formItemList.elrange, // Slider // date 、 Time 110: formItemList.eldate, // date 111: formItemList.eldate, // date + Time 112: formItemList.eldate, // years 113: formItemList.eldate, // Year week 114: formItemList.eldate, // year 115: formItemList.eltime, // At any time 116: formItemList.eltime, // Choose a fixed time // Choice 、 Switch 150: formItemList.elcheckbox, // Tick 151: formItemList.elswitch, // Switch 152: formItemList.elcheckboxs, // Multiple choice group 153: formItemList.elradios, // Single choice group 160: formItemList.elselect, // The drop-down 161: formItemList.elselwrite, // Pull down multiple choices 162: formItemList.elselect // Pull down linkage }export default { formItemList, formItemListKey}```* el-form-div.vue Code templates for form control elements ```html
```js```jsimport { watch } from 'vue'import elFormConfig from '@/components/nf-el-form/el-form-map.js'import formManage from '@/components/nf-el-form/el-form-manage.js'export default { name: 'el-form-div', components: { ...elFormConfig.formItemList }, props: { modelValue: Object, partModel: Object, meta: Object }, setup (props, context) { // Control element dictionary const ctlList = elFormConfig.formItemListKey // Form management class const { formModel, // According to meta, establish Model formColSpan, // According to meta, establish span formColSort, setFormColSpan, setFormColSort, // Set component sequencing mySubmit } = formManage(props, context) // Listen for changes in the number of columns watch(() => props.meta.formColCount, (v1, v2) => { setFormColSpan() }) // Monitoring reload watch(() => props.meta.reload, (v1, v2) => { setFormColSpan() setFormColSort() }) // Monitor changes in component values , // According to ID Get the meta, Because model No support 【】 Nest like const getCtrMeta = (id) => { return props.meta.itemMeta[id] || {} } return { formModel, formColSpan, formColSort, ctlList, getCtrMeta, mySubmit } }}``` It's much simpler here , Because the realization of specific functions js The code is all separated . How to make a sub component , To form an independent js Archives . The main task here is to re render the form components .# The form validates the use of el-form The verification function provided . We haven't summed it up yet el-form Verification of , Because you need to write the verification data to json Inside , Then read it out and set it . So it's definitely not difficult , It just takes time .# Support The components of the expansion kit are certainly not enough , Because the needs of users are always changing , How can a new component be added to a form control component ? According to the interface definition, it can be packaged into components that meet the requirements , And then make one map Dictionaries , You can set it in . Because the interface is unified , So it can adapt to the call of form control component . The simple way is , Directly modify two js Archives . If it's not convenient to modify , It can also be passed in through attributes . I haven't worked out the details yet , But it doesn't seem too hard .# Source code https://github.com/naturefwvue/nf-vue-
版权声明
本文为[itread01]所创,转载请带上原文链接,感谢
https://qdmana.com/2021/02/20210222171200282m.html

  1. 【微前端】微前端最终章-qiankun指南以及微前端整体探索
  2. Vue-Cli 创建vue3项目
  3. Go in the front of the progress of u boot v7.0 U disk boot disk production tools
  4. 使用NTLM的windows身份验证的nginx反向代理
  5. Rust教程:针对JavaScript开发人员的Rust简介
  6. 使用 Serverless Framework 部署个人博客到腾讯云
  7. #研發解決方案#易車前端監控系統
  8. Vue changes localhost to IP address and cannot access
  9. JavaScript进阶学习
  10. HTML5 from entry to proficient, realize annual salary 10W +, zero basic students must see
  11. Vue:vuex状态数据持久化插件vuex-persistedstate
  12. Vue source code analysis - start
  13. Vue -- the child component calls the method of the parent component and passes parameters --- props
  14. React-Native 获取设备当前网络状态 NetInfo
  15. 高性能 Nginx HTTPS 调优 - 如何为 HTTPS 提速 30%
  16. How to learn HTML5? How can Xiaobai start HTML5 quickly?
  17. HTML + CSS detailed tutorial, this article is enough, but also quickly save
  18. JavaScript高级:JavaScript面向对象,JavaScript内置对象,JavaScript BOM,JavaScript封装
  19. Why Vue uses asynchronous rendering
  20. JavaScript高级:JavaScript面向对象,JavaScript内置对象,JavaScript BOM,JavaScript封装
  21. vue判断elementui中el-form是否更新变化,变化就提示是否保存,没变就直接离开
  22. 算法题:两数之和——JavaScript及Java实现
  23. 高性能 Nginx HTTPS 调优
  24. Why Vue uses asynchronous rendering
  25. day 31 jQuery进阶
  26. day 30 jQuery
  27. CSS whimsy -- using background to create all kinds of wonderful backgrounds
  28. Why are more and more people learning front end?
  29. What do you do with 4K front-end development?
  30. 8 years of front-end development knowledge precipitation (do not know how many words, keep writing it...)
  31. What is the annual salary of a good web front end?
  32. Front end novice tutorial! How to get started with web front end
  33. Will the front end have a future?
  34. Is the front end hard to learn?
  35. Seven new Vue combat skills to improve efficiency in 2021!
  36. Is front end learning difficult?
  37. How about the process of Web front-end development and self-study?
  38. Front end learning route from zero basis to proficient
  39. What is the basis of learning front end?
  40. What knowledge points need to be learned for self-study front end? How long can I become a front-end Engineer?
  41. An inexperienced front-end engineer, what are the common problems when writing CSS?
  42. HttpServletRequest get URL (parameter, path, port number, protocol, etc.) details
  43. Springboot starts http2
  44. Enabling http2.0 in spring boot
  45. JQuery:JQuery基本语法,JQuery选择器,JQuery DOM,综合案例 复选框,综合案例 随机图片
  46. Using JavaScript in Safari browser history.back () the page will not refresh after returning to the previous page
  47. vue.js Error in win10 NPM install
  48. In less than two months, musk made more than $1 billion, more than Tesla's annual profit
  49. Springboot starts http2
  50. Vue event bus
  51. JQuery easy UI tutorial: custom data grid Pagination
  52. Using okhttp and okhttpgo to obtain onenet cloud platform data
  53. Vue3 component (IX) Vue + element plus + JSON = dynamic rendering form control
  54. HTTP 1. X learning notes: an authoritative guide to Web Performance
  55. Vue3 component (IX) Vue + element plus + JSON = dynamic rendering form control
  56. HTTP 1. X learning notes: an authoritative guide to Web Performance
  57. JQuery:JQuery基本语法,JQuery选择器,JQuery DOM,综合案例 复选框,综合案例 随机图片
  58. Event bubble and capture in JavaScript
  59. The root element is missing solution
  60. Event bubble and capture in JavaScript