Vue 自动配置表单 el-switch等不常用组件覆盖默认值问题
有自动解析表单的vue组件如下,其原理是调用一个配置表单定义的接口,然后再调用获取表单配置的接口并将配置的数据覆盖表单的默认值。其中el-switch的配置值没有覆盖默认值,分析其原因。 主页面如下: <template> <div class="divBox"> <el-card class="box-card"> <el-tabs v-model="activeNamel1" @tab-click="handleTabClick" v-loading="loading" v-if="checkPermi(['admin:system:config:info'])"> <el-tab-pane v-for="tab,index in treeList" :key="index" :label="tab.name" :name="tab.id.toString()"> <template> <el-tabs v-if="tab.child.length > 0" v-model="activeNamel2" type="border-card" @tab-click="handleItemTabClick"> <el-tab-pane v-for="tabItem,itemIndex in tab.child" :key="itemIndex" :label="tabItem.name" :name="tabItem.extra" > <parser v-if="formConfChild.render" :is-edit="formConfChild.isEdit" :form-conf="formConfChild.content" :form-edit-data="currentEditData" @submit="handlerSubmit" /> </el-tab-pane> </el-tabs> <span v-else> <parser v-if="formConf.render" :is-edit="formConf.isEdit" :form-conf="formConf.content" :form-edit-data="currentEditData" @submit="handlerSubmit" /> </span> </template> </el-tab-pane> </el-tabs> </el-card> </div> </template> <script> import parser from '@/components/FormGenerator/components/parser/Parser' import * as categoryApi from '@/api/categoryApi.js' import * as selfUtil from '@/utils/XMutil.js' import * as systemFormConfigApi from '@/api/systemFormConfig.js' import * as systemSettingApi from '@/api/systemSetting.js' import * as systemConfigApi from '@/api/systemConfig.js' import Template from "@/views/appSetting/wxAccount/wxTemplate/index"; import {beautifierConf} from "@/components/FormGenerator/utils"; import { checkPermi } from "@/utils/permission"; // 权限判断函数 import {Debounce} from '@/utils/validate' export default { // name: "index", components: {Template, parser }, data() { return { loading: false, formConf: { content: { fields: [] }, id: null, render: false, isEdit: false }, formConfChild: { content: { fields: [] }, id: null, render: false, isEdit: false }, activeNamel1: null, activeNamel2: '',//针对文件特殊处理 treeList: [], editDataChild: {}, isCreate: 0, currentEditId: null, currentEditData: null, currentSelectedUploadFlag:null, } }, mounted() { this.handlerGetTreeList() this.getCurrentUploadSelectedFlag() }, methods: { checkPermi, handleTabClick(tab) { this.activeNamel2 = tab.$children[0].panes[0].name; this.handlerGetLevel2FormConfig(this.activeNamel2); }, handlerGetLevel1FormConfig(id) { const formPram = { id: id } this.currentEditId = id this.formConf.content = { fields: [] } this.formConf.render = false this.loading = true systemFormConfigApi.getFormConfigInfo(formPram).then(data => { const { id, name, info, content } = data this.formConf.content = JSON.parse(content) this.formConf.id = id this.handlerGetSettingInfo(id, 1) this.loading = false }).catch(() =>{ this.loading = false }) }, handleItemTabClick(tab, event) { //这里对tabs=tab.name和radio=id做了兼容 let _id = tab.name ? tab.name : tab if(!_id) return this.$message.error('表单配置不正确,请关联正确表单后使用') this.handlerGetLevel2FormConfig(_id) }, handlerGetLevel2FormConfig(id) { const formPram = { id: id } this.currentEditId = id this.formConfChild.content = { fields: [] } this.formConfChild.render = false this.loading = true systemFormConfigApi.getFormConfigInfo(formPram).then(data => { const { id, name, info, content } = data this.formConfChild.content = JSON.parse(content) this.formConfChild.id = id this.handlerGetSettingInfo(id, 2) this.loading = false }).catch(() =>{ this.loading = false }) }, handlerGetSettingInfo(id, level) { systemSettingApi.systemConfigInfo({ id: id }).then(data => { this.currentEditData = data if (level === 1) { this.formConf.isEdit = this.currentEditData !== null this.formConf.render = true } else { this.formConfChild.isEdit = this.currentEditData !== null this.formConfChild.render = true } }) }, handlerSubmit:Debounce(function(formValue) { this.handlerSave(formValue) }), handlerSave(formValue) { const _pram = this.buildFormPram(formValue) let _formId = 0 systemSettingApi.systemConfigSave(_pram).then(data => { this.$message.success('添加数据成功') }) }, handlerGetTreeList() { const _pram = { type: this.$constants.categoryType[5].value, status: 1 } this.loading = true categoryApi.treeCategroy(_pram).then(data => { this.treeList = this.handleAddArrt(data) if (this.treeList.length > 0) this.activeNamel1 = this.treeList[0].id.toString(); if (this.treeList.length > 0 && this.treeList[0].child.length > 0) { this.activeNamel2 = this.treeList[0].child[0].extra } if (this.activeNamel2) { this.handlerGetLevel2FormConfig(this.treeList[0].child[0].extra) } // else { // this.handlerGetLevel1FormConfig(this.treeList[0].extra) //} this.loading = false }).catch(() =>{ this.loading = false }) }, handleAddArrt(treeData) { // let _result = this.addTreeListLabel(treeData) const _result = selfUtil.addTreeListLabel(treeData) return _result }, buildFormPram(formValue) { const _pram = { fields: [], id: this.currentEditId, sort: 0, // 参数暂时无用 status: true // 参数暂时无用 } const _fields = [] Object.keys(formValue).forEach((key) => { _fields.push({ name: key, title: key, value: formValue[key] }) }) _pram.fields = _fields return _pram }, getCurrentUploadSelectedFlag(){ systemConfigApi.configGetUniq({key:"uploadType"}).then(data => { this.currentSelectedUploadFlag = parseInt(data) }) } } } </script> <style scoped> </style> 获取表单定义的接口及报文如下: http://127.0.0.1:8080/api/admin/system/form/temp/info?id=77&temp=1739687295 { "code": 200, "message": "操作成功", "data": { "id": 77, "name": "商城基础配置", "info": "商城配置-商城基础配置", "content": "{\"formRef\":\"elForm\",\"formModel\":\"formData\",\"size\":\"medium\",\"labelPosition\":\"right\",\"labelWidth\":300,\"formRules\":\"rules\",\"gutter\":15,\"disabled\":false,\"span\":24,\"formBtns\":true,\"fields\":[{\"__config__\":{\"label\":\"商品捐赠是否开启\",\"tag\":\"el-switch\",\"tagIcon\":\"switch\",\"defaultValue\":true,\"span\":24,\"showLabel\":true,\"labelWidth\":null,\"layout\":\"colFormItem\",\"required\":true,\"tips\":false,\"tipsDesc\":\"\",\"tipsIsLink\":false,\"tipsLink\":\"\",\"regList\":[],\"changeTag\":true,\"document\":\"Element - The world's most popular Vue UI framework \",\"formId\":102,\"renderKey\":1738534828949},\"style\":{},\"disabled\":false,\"active-text\":\"\",\"inactive-text\":\"\",\"active-color\":null,\"inactive-color\":null,\"active-value\":true,\"inactive-value\":false,\"__vModel__\":\"donation\"},{\"__config__\":{\"label\":\"商品捐赠比例设置\",\"tag\":\"el-input-number\",\"tagIcon\":\"number\",\"defaultValue\":19,\"span\":24,\"showLabel\":true,\"layout\":\"colFormItem\",\"labelWidth\":\"\",\"required\":true,\"tips\":false,\"tipsDesc\":\"\",\"tipsIsLink\":false,\"tipsLink\":\"\",\"regList\":[],\"changeTag\":true,\"document\":\"Element - The world's most popular Vue UI framework \",\"formId\":103,\"renderKey\":1738534896059},\"disabled\":false,\"min\":0,\"max\":100,\"step\":1,\"show-stops\":false,\"range\":false,\"__vModel__\":\"donation_rate\"},{\"__config__\":{\"label\":\"警戒库存\",\"showLabel\":true,\"changeTag\":true,\"labelWidth\":300,\"tag\":\"el-input-number\",\"tagIcon\":\"number\",\"span\":24,\"layout\":\"colFormItem\",\"required\":true,\"regList\":[],\"document\":\"Element - The world's most popular Vue UI framework \",\"formId\":102,\"renderKey\":1590032029141,\"defaultValue\":2,\"tips\":false},\"placeholder\":\"警戒库存\",\"step\":1,\"step-strictly\":false,\"controls-position\":\"\",\"disabled\":false,\"__vModel__\":\"store_stock\",\"max\":99999,\"min\":0},{\"__config__\":{\"label\":\"退货理由\",\"labelWidth\":300,\"showLabel\":true,\"tag\":\"el-input\",\"tagIcon\":\"textarea\",\"required\":true,\"layout\":\"colFormItem\",\"span\":24,\"regList\":[],\"changeTag\":true,\"document\":\"Element - The world's most popular Vue UI framework \",\"formId\":103,\"renderKey\":1590032054065,\"defaultValue\":\"收货地址填错了 与描述不符 信息填错了,重新拍 收到商品损坏了 未按预定时间发货 其它原因\",\"tips\":false},\"type\":\"textarea\",\"placeholder\":\"请填写退货理由退货理由\",\"autosize\":{\"minRows\":4,\"maxRows\":4},\"style\":{\"width\":\"100%\"},\"maxlength\":null,\"show-word-limit\":false,\"readonly\":false,\"disabled\":false,\"__vModel__\":\"stor_reason\"},{\"__config__\":{\"label\":\"移动端顶部logo图标(127*45)\",\"tag\":\"self-upload\",\"tagIcon\":\"upload\",\"layout\":\"colFormItem\",\"defaultValue\":null,\"showLabel\":true,\"labelWidth\":300,\"required\":true,\"span\":24,\"showTip\":false,\"buttonText\":\"点击上传\",\"regList\":[],\"changeTag\":true,\"fileSize\":2,\"sizeUnit\":\"MB\",\"document\":\"Element - The world's most popular Vue UI framework \",\"formId\":124,\"renderKey\":1595659136385,\"tips\":false},\"__slot__\":{\"list-type\":true},\"action\":\"https://jsonplaceholder.typicode.com/posts/ \",\"disabled\":true,\"accept\":\"\",\"name\":\"file\",\"auto-upload\":true,\"list-type\":\"text\",\"multiple\":false,\"__vModel__\":\"mobile_top_logo\"},{\"__config__\":{\"label\":\"移动端登录页logo(90x90)\",\"tag\":\"self-upload\",\"tagIcon\":\"upload\",\"layout\":\"colFormItem\",\"defaultValue\":null,\"showLabel\":true,\"labelWidth\":300,\"required\":true,\"span\":24,\"showTip\":false,\"buttonText\":\"点击上传\",\"regList\":[],\"changeTag\":true,\"fileSize\":2,\"sizeUnit\":\"MB\",\"document\":\"Element - The world's most popular Vue UI framework \",\"formId\":102,\"renderKey\":1629094835969,\"tips\":false},\"__slot__\":{\"list-type\":true},\"action\":\"https://jsonplaceholder.typicode.com/posts/ \",\"disabled\":true,\"accept\":\"\",\"name\":\"file\",\"auto-upload\":true,\"list-type\":\"text\",\"multiple\":false,\"__vModel__\":\"mobile_login_logo\"},{\"__config__\":{\"label\":\"普通商品未支付取消订单时间(单位:小时)\",\"showLabel\":true,\"changeTag\":true,\"labelWidth\":300,\"tag\":\"el-input-number\",\"tagIcon\":\"number\",\"span\":24,\"layout\":\"colFormItem\",\"required\":true,\"regList\":[],\"document\":\"Element - The world's most popular Vue UI framework \",\"formId\":105,\"renderKey\":1590032096481,\"defaultValue\":2,\"tips\":false},\"placeholder\":\"普通商品未支付取消订单时间(单位:小时)\",\"step\":1,\"step-strictly\":false,\"controls-position\":\"\",\"disabled\":false,\"__vModel__\":\"order_cancel_time\",\"max\":99999,\"min\":0,\"precision\":0},{\"__config__\":{\"label\":\"活动商品未支付取消订单时间(单位小时)\",\"showLabel\":true,\"changeTag\":true,\"labelWidth\":300,\"tag\":\"el-input-number\",\"tagIcon\":\"number\",\"span\":24,\"layout\":\"colFormItem\",\"required\":true,\"regList\":[],\"document\":\"Element - The world's most popular Vue UI framework \",\"formId\":106,\"renderKey\":1590032112020,\"defaultValue\":2,\"tips\":false},\"placeholder\":\"活动商品未支付取消订单时间(单位:小时)\",\"step\":1,\"step-strictly\":false,\"controls-position\":\"\",\"disabled\":false,\"__vModel__\":\"order_activity_time\",\"max\":99999,\"min\":0,\"precision\":0},{\"__config__\":{\"label\":\"网站名称\",\"labelWidth\":null,\"showLabel\":true,\"changeTag\":true,\"tag\":\"el-input\",\"tagIcon\":\"input\",\"required\":true,\"layout\":\"colFormItem\",\"span\":24,\"document\":\"Element - The world's most popular Vue UI framework \",\"regList\":[],\"formId\":101,\"renderKey\":1629086692739,\"tips\":false},\"__slot__\":{\"prepend\":\"\",\"append\":\"\"},\"placeholder\":\"请输入网站名称\",\"style\":{\"width\":\"100%\"},\"clearable\":true,\"prefix-icon\":\"\",\"suffix-icon\":\"\",\"maxlength\":null,\"show-word-limit\":false,\"readonly\":false,\"disabled\":false,\"__vModel__\":\"site_name\"},{\"__config__\":{\"label\":\"网站地址\",\"labelWidth\":null,\"showLabel\":true,\"changeTag\":true,\"tag\":\"el-input\",\"tagIcon\":\"input\",\"required\":true,\"layout\":\"colFormItem\",\"span\":24,\"document\":\"Element - The world's most popular Vue UI framework \",\"regList\":[],\"formId\":102,\"renderKey\":1629086763346,\"tips\":false},\"__slot__\":{\"prepend\":\"\",\"append\":\"\"},\"placeholder\":\"webSiet网站地址网站地址网站地址\",\"style\":{\"width\":\"100%\"},\"clearable\":true,\"prefix-icon\":\"\",\"suffix-icon\":\"\",\"maxlength\":null,\"show-word-limit\":true,\"readonly\":false,\"disabled\":false,\"__vModel__\":\"site_url\"},{\"__config__\":{\"label\":\"SEO标题\",\"labelWidth\":null,\"showLabel\":true,\"changeTag\":true,\"tag\":\"el-input\",\"tagIcon\":\"input\",\"required\":true,\"layout\":\"colFormItem\",\"span\":24,\"document\":\"Element - The world's most popular Vue UI framework \",\"regList\":[],\"formId\":102,\"renderKey\":1629087874359,\"tips\":false},\"__slot__\":{\"prepend\":\"\",\"append\":\"\"},\"placeholder\":\"请输入SEO标题\",\"style\":{\"width\":\"100%\"},\"clearable\":true,\"prefix-icon\":\"\",\"suffix-icon\":\"\",\"maxlength\":null,\"show-word-limit\":false,\"readonly\":false,\"disabled\":false,\"__vModel__\":\"seo_title\"},{\"__config__\":{\"label\":\"新闻幻灯片数量上限\",\"showLabel\":true,\"changeTag\":true,\"labelWidth\":null,\"tag\":\"el-input-number\",\"tagIcon\":\"number\",\"span\":24,\"layout\":\"colFormItem\",\"required\":true,\"regList\":[],\"document\":\"Element - The world's most popular Vue UI framework \",\"formId\":101,\"renderKey\":1629087608122,\"defaultValue\":1,\"tips\":false},\"placeholder\":\"新闻幻灯片数量上限新闻幻灯片数量上限新闻幻灯片数量上限新闻幻灯片数量上限\",\"step\":1,\"step-strictly\":false,\"controls-position\":\"\",\"disabled\":false,\"__vModel__\":\"news_slides_limit\",\"min\":1,\"max\":3},{\"__config__\":{\"label\":\"移动商城api\",\"labelWidth\":null,\"showLabel\":true,\"changeTag\":true,\"tag\":\"el-input\",\"tagIcon\":\"input\",\"required\":true,\"layout\":\"colFormItem\",\"span\":24,\"document\":\"Element - The world's most popular Vue UI framework \",\"regList\":[],\"formId\":101,\"renderKey\":1639127436585,\"tips\":false},\"__slot__\":{\"prepend\":\"\",\"append\":\"\"},\"placeholder\":\"移动商城api_小程序源码下载前必须配置\",\"style\":{\"width\":\"100%\"},\"clearable\":true,\"prefix-icon\":\"\",\"suffix-icon\":\"\",\"maxlength\":null,\"show-word-limit\":true,\"readonly\":false,\"disabled\":false,\"__vModel__\":\"front_api_url\"}]}", "createTime": "2020-05-16 02:19:37", "updateTime": "2025-02-16 14:27:39" } } 获取配置的接口及报文如下: api/admin/system/config/info?formId=77&temp=1739687295 { "code": 200, "message": "操作成功", "data": { "news_slides_limit": "3", "mobile_login_logo": "http://127.0.0.1:8080/yczjimage/public/operation/2025/02/02/71622984926b44a485fc962f153804ecddvigsrbm3.jpg ", "donation_rate": "19", "store_stock": "22", "order_cancel_time": "1", "mobile_top_logo": "http://127.0.0.1:8080/yczjimage/public/maintain/2021/12/25/54d7a09f1dee463fa12ec01c02294b31z66prnux9w.png ", "seo_title": "一码秦川", "site_name": "一马秦川", "order_activity_time": "1", "stor_reason": "收货地址填错了\n与描述不符 \n信息填错了,重新拍 \n收到商品损坏了 \n未按预定时间发货 \n其它原因\n测试111", "site_url": "https://app.net ", "donation": "true", "id": "77", "front_api_url": "http://127.0.0.1:8081 " } } 表单组件转化的Vue组件如下: <script> import render from '@/components/FormGenerator/components/render/render.js' const ruleTrigger = { 'el-input': 'blur', 'el-input-number': 'blur', 'el-switch': 'change', 'el-select': 'change', 'el-radio-group': 'change', 'el-checkbox-group': 'change', 'el-cascader': 'change', 'el-time-picker': 'change', 'el-date-picker': 'change', 'el-rate': 'change' } function renderFrom(h) { const { formConfCopy } = this return ( <el-row gutter={formConfCopy.gutter}> <el-form size={formConfCopy.size} label-position={formConfCopy.labelPosition} disabled={formConfCopy.disabled} label-width={`${formConfCopy.labelWidth}px`} ref={formConfCopy.formRef} // model不能直接赋值 https://github.com/vuejs/jsx/issues/49#issuecomment-472013664 props={{ model: this[formConfCopy.formModel] }} rules={this[formConfCopy.formRules]} > {renderFormItem.call(this, h, formConfCopy.fields)} {formConfCopy.formBtns && formBtns.call(this, h)} </el-form> </el-row> ) } function formBtns(h) { return <el-col> <el-form-item size='mini'> <el-button type='primary' onClick={this.submitForm}>提交</el-button> </el-form-item> </el-col> } function renderFormItem(h, elementList) { return elementList.map(scheme => { const config = scheme.__config__ const layout = layouts[config.layout] if (layout) { return layout.call(this, h, scheme) } throw new Error(`没有与${config.layout}匹配的layout`) }) } function renderChildren(h, scheme) { const config = scheme.__config__ if (!Array.isArray(config.children)) return null return renderFormItem.call(this, h, config.children) } function setValue(event, config, scheme) { this.$set(config, 'defaultValue', event) this.$set(this[this.formConf.formModel], scheme.__vModel__, event) } function buildListeners(scheme) { const config = scheme.__config__ const methods = this.formConf.__methods__ || {} const listeners = {} // 给__methods__中的方法绑定this和event Object.keys(methods).forEach(key => { listeners[key] = event => methods[key].call(this, event) }) // 响应 render.js 中的 vModel $emit('input', val) listeners.input = event => setValue.call(this, event, config, scheme) return listeners } const layouts = { colFormItem(h, scheme) { const config = scheme.__config__ const listeners = buildListeners.call(this, scheme) let labelWidth = config.labelWidth ? `${config.labelWidth}px` : null if (config.showLabel === false) labelWidth = '0' if(config.tips && !config.tipsIsLink){ return ( <el-col span={config.span}> <el-form-item label-width={labelWidth} prop={scheme.__vModel__} label={config.showLabel ? config.label : ''}> <el-tooltip effect="dark" placement="top-start" style="padding:10px 5px 0 0;"> <i class="el-icon-warning-outline" /> <div slot="content" style="max-width:400px;">{config.tipsDesc}</div> </el-tooltip> <render conf={scheme} {...{ on: listeners }} /> </el-form-item> </el-col> ) }else if(config.tips && config.tipsIsLink){ return ( <el-col span={config.span}> <el-form-item label-width={labelWidth} prop={scheme.__vModel__} label={config.showLabel ? config.label : ''}> <el-tooltip effect="dark" placement="top-start" style="padding:10px 5px 0 0;"> <i class="el-icon-warning-outline" /> <div slot="content" style="max-width:400px;"> <a href={config.tipsLink} target="_blank">{config.tipsDesc}</a> </div> </el-tooltip> <render conf={scheme} {...{ on: listeners }} /> </el-form-item> </el-col> ) }else{ return ( <el-col span={config.span}> <el-form-item label-width={labelWidth} prop={scheme.__vModel__} label={config.showLabel ? config.label : ''}> <render conf={scheme} {...{ on: listeners }} /> </el-form-item> </el-col> ) } }, rowFormItem(h, scheme) { let child = renderChildren.apply(this, arguments) if (scheme.type === 'flex') { child = <el-row type={scheme.type} justify={scheme.justify} align={scheme.align}> {child} </el-row> } return ( <el-col span={scheme.span}> <el-row gutter={scheme.gutter}> {child} </el-row> </el-col> ) } } export default { components: { render }, props: { formConf: { type: Object, required: true }, formEditData: { type: Object }, isEdit: { type: Boolean, default: false } }, data() { if (this.isEdit) { // 初始化待编辑数据 this.formConf.fields.forEach(conf => { // 设置现有的数据 const hasValueForEdit = this.formEditData[conf.__vModel__] if(hasValueForEdit){ conf.__config__.defaultValue = hasValueForEdit } // 如果是el-select标签 判断数据后改变实现默认选中效果 if(conf.__config__.tag === 'el-select' || conf.__config__.tag === 'el-radio-group'){ const perValue = conf.__slot__.options.filter(option => option.value == this.formEditData[conf.__vModel__]) if(perValue.length > 0){ // 有表单数据 conf.__config__.defaultValue = perValue[0].value } } }) } const data = { formConfCopy: JSON.parse(JSON.stringify(this.formConf)), [this.formConf.formModel]: {}, [this.formConf.formRules]: {} } this.initFormData(data.formConfCopy.fields, data[this.formConf.formModel]) this.buildRules(data.formConfCopy.fields, data[this.formConf.formRules]) return data }, methods: { initFormData(componentList, formData) { componentList.forEach(cur => { const config = cur.__config__ if (cur.__vModel__) formData[cur.__vModel__] = config.defaultValue if (config.children) this.initFormData(config.children, formData) }) }, buildRules(componentList, rules) { componentList.forEach(cur => { const config = cur.__config__ if (Array.isArray(config.regList)) { if (config.required) { const required = { required: config.required, message: cur.placeholder } if (Array.isArray(config.defaultValue)) { required.type = 'array' required.message = `请至少选择一个${config.label}` } required.message === undefined && (required.message = `${config.label}不能为空`) config.regList.push(required) } rules[cur.__vModel__] = config.regList.map(item => { item.pattern && (item.pattern = eval(item.pattern)) item.trigger = ruleTrigger && ruleTrigger[config.tag] return item }) } if (config.children) this.buildRules(config.children, rules) }) }, resetForm() { this.$emit('resetForm', this.formConf) this.formConfCopy = JSON.parse(JSON.stringify(this.formConf)) this.$refs[this.formConf.formRef].resetFields() }, submitForm() { this.$refs[this.formConf.formRef].validate(valid => { if (!valid) return false // 触发sumit事件 this.$emit('submit', this[this.formConf.formModel]) return true }) } }, render(h) { return renderFrom.call(this, h) } } </script> 组件渲染的js如下: function vModel(self, dataObject, defaultValue) { dataObject.props.value = defaultValue dataObject.on.input = val => { self.$emit('input', val) } } const componentChild = {} /** * 将./slots中的文件挂载到对象componentChild上 * 文件名为key,对应JSON配置中的__config__.tag * 文件内容为value,解析JSON配置中的__slot__ */ const slotsFiles = require.context('./slots', true, /\.js$/) const keys = slotsFiles.keys() || [] keys.forEach(key => { const tag = key.replace(/^\.\/(.*)\.\w+$/, '$1') const value = slotsFiles(key).default componentChild[tag] = value }) export default { render(h) { const dataObject = { attrs: {}, props: {}, on: {}, style: {} } const confClone = JSON.parse(JSON.stringify(this.conf)) const children = [] const childObjs = componentChild[confClone.__config__.tag] if (childObjs) { Object.keys(childObjs).forEach(key => { const childFunc = childObjs[key] if (confClone.__slot__ && confClone.__slot__[key]) { children.push(childFunc(h, confClone, key)) } }) } Object.keys(confClone).forEach(key => { const val = confClone[key] if (key === '__vModel__') { vModel(this, dataObject, confClone.__config__.defaultValue) } else if (dataObject[key]) { console.log(`__vModel__: ${JSON.stringify(dataObject)}`) dataObject[key] = { ...dataObject[key], ...val } } else { dataObject.attrs[key] = val } }) delete dataObject.attrs.__config__ delete dataObject.attrs.__slot__ return h(this.conf.__config__.tag, dataObject, children) }, props: ['conf'] }
从代码和接口报文来看,el-switch
的配置值没有覆盖默认值的原因可能如下:
1. 数据绑定问题
在 parser
组件的 data
中,formConfCopy
是通过 JSON.parse(JSON.stringify(this.formConf))
深拷贝而来。而 formConf
是通过接口获取的表单定义数据,其中 el-switch
的配置如下:
JSONCopy
{"__config__": {"label": "商品捐赠是否开启","tag": "el-switch","tagIcon": "switch","defaultValue": true,"span": 24,"showLabel": true,"labelWidth": null,"layout": "colFormItem","required": true,"tips": false,"tipsDesc": "","tipsIsLink": false,"tipsLink": "","regList": [],"changeTag": true,"document": "https://element.eleme.cn/#/zh-CN/component/switch","formId": 102,"renderKey": 1738534828949},"style": {},"disabled": false,"active-text": "","inactive-text": "","active-color": null,"inactive-color": null,"active-value": true,"inactive-value": false,"__vModel__": "donation"
}
在 parser
组件的 data
初始化时,formConfCopy
的 fields
中的每个配置项的 __config__.defaultValue
会被赋值给 formData
对应的字段(通过 initFormData
方法)。但是,el-switch
的 __vModel__
是 donation
,而接口返回的配置数据中 donation
的值是 "true"
(字符串),而不是 true
(布尔值)。
JSONCopy
"donation": "true"
这可能导致 el-switch
的值没有正确绑定,因为 el-switch
的 active-value
和 inactive-value
分别是 true
和 false
(布尔值),而绑定的值是字符串 "true"
,类型不匹配。
2. 数据更新问题
在 parser
组件的 data
初始化时,虽然会根据 formEditData
更新 formConfCopy.fields
中的 __config__.defaultValue
,但是 el-switch
的值没有正确更新。
在 parser
组件的 data
初始化代码中:
JavaScriptCopy
if (this.isEdit) { // 初始化待编辑数据this.formConf.fields.forEach(conf => {// 设置现有的数据const hasValueForEdit = this.formEditData[conf.__vModel__]if(hasValueForEdit){conf.__config__.defaultValue = hasValueForEdit}// 如果是el-select标签 判断数据后改变实现默认选中效果if(conf.__config__.tag === 'el-select' || conf.__config__.tag === 'el-radio-group'){const perValue = conf.__slot__.options.filter(option => option.value == this.formEditData[conf.__vModel__])if(perValue.length > 0){ // 有表单数据conf.__config__.defaultValue = perValue[0].value}}})
}
这里只处理了 el-select
和 el-radio-group
的情况,没有处理 el-switch
的情况。因此,el-switch
的值没有被正确更新。
3. 组件渲染问题
在组件渲染的 render.js
中,vModel
函数会根据 __vModel__
和 __config__.defaultValue
设置 dataObject.props.value
,并绑定 input
事件。
JavaScriptCopy
function vModel(self, dataObject, defaultValue) {dataObject.props.value = defaultValuedataObject.on.input = val => {self.$emit('input', val)}
}
但是,el-switch
的值是布尔值,而绑定的值是字符串 "true"
,这可能导致 el-switch
的值没有正确渲染。
解决方法
-
修正接口返回的数据类型:确保接口返回的
donation
的值是布尔值true
,而不是字符串"true"
。 -
在
parser
组件中处理el-switch
的值:在data
初始化时,添加对el-switch
的处理逻辑,将字符串"true"
转换为布尔值true
。
JavaScriptCopy
if (this.isEdit) { // 初始化待编辑数据this.formConf.fields.forEach(conf => {// 设置现有的数据const hasValueForEdit = this.formEditData[conf.__vModel__]if(hasValueForEdit){if(conf.__config__.tag === 'el-switch'){ // 处理 el-switch 的值conf.__config__.defaultValue = hasValueForEdit === "true" ? true : false}else{conf.__config__.defaultValue = hasValueForEdit}}// 如果是el-select标签 判断数据后改变实现默认选中效果if(conf.__config__.tag === 'el-select' || conf.__config__.tag === 'el-radio-group'){const perValue = conf.__slot__.options.filter(option => option.value == this.formEditData[conf.__vModel__])if(perValue.length > 0){ // 有表单数据conf.__config__.defaultValue = perValue[0].value}}})
}
-
在组件渲染的
render.js
中处理el-switch
的值:在vModel
函数中,添加对el-switch
的处理逻辑,将字符串"true"
转换为布尔值true
。
JavaScriptCopy
function vModel(self, dataObject, defaultValue) {if(self.conf.__config__.tag === 'el-switch'){ // 处理 el-switch 的值dataObject.props.value = defaultValue === "true" ? true : false}else{dataObject.props.value = defaultValue}dataObject.on.input = val => {self.$emit('input', val)}
}
相关文章:
Vue 自动配置表单 el-switch等不常用组件覆盖默认值问题
有自动解析表单的vue组件如下,其原理是调用一个配置表单定义的接口,然后再调用获取表单配置的接口并将配置的数据覆盖表单的默认值。其中el-switch的配置值没有覆盖默认值,分析其原因。 主页面如下: <template> <div cla…...

零基础购买阿里云服务器,XShell连接云服务器
目录 1.环境搭建方式 2. 使用云服务器 3.使用终端软件登录到Linux 4.使用XShell登录主机 5.连接失败的原因: 下一篇更新:Linux的基础指令以及如何Linux的环境搭建 1.环境搭建方式 主要有四种: 1.直接安装在物理机上,虽然Linux有图形化…...

【系统架构设计师】虚拟机体系结构风格
目录 1. 说明2. 解释器体系结构风格3. 规则系统体系结构风格4. 例题4.1 例题1 1. 说明 1.p263。2.虚拟机体系结构风格的基本思想是人为构建一个运行环境,在这个环境之上,可以解析与运行自定义的一些语言,这样来增加架构的灵活性。3.虚拟机体…...

C语言中qsort函数使用技巧
在C语言的标准库中, qsort 函数是一个强大的通用排序函数,它采用快速排序算法,能够高效地对各种数据类型的数组进行排序。掌握 qsort 函数的使用技巧,对于提升程序的效率和代码的简洁性至关重要。 一、qsort函数基本介绍 qsort 函…...

WPF的Prism框架的使用
安装Prism.DryIoc库: Prism的区域和模块化: 一个区域可以显示一个用户控件 一个模块就是一个项目,也就是一个类库 动态切换用户控件的案例: <Grid><Grid.RowDefinitions><RowDefinition Height"auto"…...

LeetCode每日精进:142.环形链表II
题目链接:142.环形链表II 题目描述: 给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环…...

CPP集群聊天服务器开发实践(五):nginx负载均衡配置
1 负载均衡器的原理与功能 单台Chatserver可以容纳大约两万台客户端同时在线聊天,为了提升并发量最直观的办法需要水平扩展服务器的数量,三台服务器可以容纳六万左右的客户端。 负载均衡器的作用: 把client的请求按照负载均衡算法分发到具体…...
easyexcel解析excel文件的时候报错
easyexcel解析xls文件的时候,报错Exception in thread "main" com.alibaba.excel.exception.ExcelAnalysisException: java.lang.NoClassDefFoundError: org/objectweb/asm/Type at com.alibaba.excel.analysis.ExcelAnalyserImpl.analysis(ExcelAnalyser…...

Android设备 网络安全检测
八、网络与安全机制 6.1 网络框架对比 volley: 功能 基于HttpUrlConnection;封装了UIL图片加载框架,支持图片加载;网络请求的排序、优先级处理缓存;多级别取消请求;Activity和生命周期的联动(Activity结束生命周期同时取消所有网络请求 …...

word分栏使得最后一页内容自动平衡
word分栏使得最后一页内容自动平衡 Word中的分页符分节符 Word中的分页符与分节符统称为分隔符 【分页符】 是将一页内容分成两页, 但分离后的两页属于同一节;分页符用于强制在当前位置分页, 后续内容从下一页开始;分页符对应快捷键 Ctrl Enter ; 【分节符】 分节符用…...

完全免费稳定WebTerm网页版在线SSH连接,在线远程连接云服务器,可以控制背景,支持SFTP访问服务器文件。无需安装即可在线连接和管理服务器的SSH终端工具。支持跨平台设备。
目录 用途介绍 网页版SSH使用说明及教程 首次登录配置 设置中心介绍 编辑 SFTP功能 用途介绍 各位开发者在使用远程服务器时经常面临一个很致命的问题,就是当没有在使用自己电脑,远程服务器商家又没有提供在线的VNC连接,这时重新去安装…...

微信小程序医院挂号系统
第3章 系统设计 3.1系统体系结构 系统的体系结构非常重要,往往决定了系统的质量和生命周期。针对不同的系统可以采用不同的系统体系结构。本系统为微信小程序医院挂号系统,属于开放式的平台,所以在管理端体系结构中采用B/s。B/s结构抛弃了固…...
编程题-最大子数组和(中等-重点【贪心、动态规划、分治思想的应用】)
题目: 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 子数组是数组中的一个连续部分。 解法一(枚举法-时间复杂度超限): …...
阿里云视频点播,基于thinkphp8上传视频
前端参考官方示例(jQuery版) <!DOCTYPE html> <html> <head><meta charset"utf-8"><title>阿里云 JavaScript上传SDK Demo (使用jquery)</title><script src"__STATIC__/jquery.min.js"></script><sc…...
《探秘AI绿色计算:降低人工智能硬件能耗的热点技术》
在人工智能飞速发展的当下,其硬件能耗问题愈发凸显。据国际能源署预测,人工智能的能源消耗可能大幅增长。因此,降低人工智能硬件能耗,实现绿色计算,已成为行业关键课题。以下是一些正在崭露头角的热点技术。 新型硬件…...

神经网络常见激活函数 9-CELU函数
文章目录 CELU函数导函数函数和导函数图像优缺点pytorch中的CELU函数tensorflow 中的CELU函数 CELU 连续可微指数线性单元:CELU(Continuously Differentiable Exponential Linear Unit),是一种连续可导的激活函数,结合了 ELU 和 …...
软考高级《系统架构设计师》知识点(四)
嵌入式技术 第二版新增内容 嵌入式系统:以应用为中心、以计算机技术为基础,并将可配置与可裁减的软、硬件、集成于一体的专用计算机系统,需要满足应用对功能、可靠性、成本、体积和功耗等方面的严格要求。一般嵌入式系统由嵌入式处理器、相关…...
opencv交叉编译
适用于瑞芯微,海思,酷芯等ARM平台。采用编译脚本配置编译选项,方便编译。 目录 一、创建目录 二、工具链配置 三、编译脚本 四、编译 一、创建目录 mikemike-virtual-machine:opencv-4.12/opencv/opencv$ tree . -L 1 . ├── 3rdpart…...

安装vite报错Install for [ ‘create-vite@latest‘ ] failed with code 1
报错内容: npm ERR! code ENOLOCAL npm ERR! Could not install from “Files\nodejs\node_cache_npx\31400” as it does not contain a package.json file. npm ERR! A complete log of this run can be found in: npm ERR! D:\Program Files\nodejs\node_cache_…...

Spring框架中都用到了哪些设计模式?
大家好,我是锋哥。今天分享关于【Spring框架中都用到了哪些设计模式?】面试题。希望对大家有帮助; Spring框架中都用到了哪些设计模式? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Spring框架中使用了大量的设计模…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...

Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...