vue3 低代码自定义配置邮箱邮件模板(一)
低代码配置
约定低代码配置,数据解析分为两层。
{
theme: "#ff6600",
data: {
},
form: {
}
}
theme: 模板主题,对应颜色值
data: {} 对应数据
form: {} 表单配置
约定配置数据为两级的意思是说,form内部存在表单嵌套的情况,那么对应的数据也是两级,然后实现表单渲染关联数据就可以实现一一对应。
form: {
title: {
name: "邮件标题",
showName: false,
top: 1,
text: {
top: 1,
showLabel: false,
componentsProps: {
showCount: true,
maxlength: 100,
autoSize: { minRows: 1, maxRows: 1 }
},
rules: [
{ required: true, message: "请输入邮件标题" },
{ max: 100, message: "最多只能输入100个字符" }
],
colSpan: 24,
placeholder: "请在这里输入邮件标题",
type: "TextareaInput",
label: "邮件标题"
}
}
}
对应数据格式
data: {
theme: "#00A870",
title: {
text: ""
},
}
则此时可以试下表单和数据的对应关系。
theme: {
"#00A870": {
name: "绿色"
},
"#0593CC": {
name: "天蓝色"
},
"#3F43BA": {
name: "蓝色"
},
"#2D206F": {
name: "紫色"
}
}
这里是颜色风格
经过以上表单解析和对应的关联数据结构。
这样我们通过配置表单和和对应数据就可以实现丰富的邮件模板样式。
表单解析和数据关联
前端组件库使用的是antd-vue 2 版本,该版本组件库支持,直接给formItem配置rules以及关联校验时关联的层级数据。很容易实现数据的双向绑定。
html模板结构太大,这里截图演示。
首先根据,form表单配置部分解析并渲染form表单,因为表单有分组(即某个配置下可能有多个表单元项)的情况,所以先要通过通过一个空formItem实现对分组formItem的渲染,实现label展示,这里并不关联数据和表单项,仅仅只展示label。
其次,因为表单结构可能比较复杂,并不适合使用antd vue 表单的layout来划分列和行,所以采用inline模式,自己更加自由的通过配置样式来控制表单的展示列和行,举个例子。24栅格可能并不能完美实现表单设计的宽窄,所以我们采用inline,并通过配置列宽(支持小数),然后动态计算宽度,来实现更加精确的列宽控制。然后通过24 来实现占据整行,非24 则计算出来实际宽度。比沟通过配置由嵌套key组成的class来实现自定义样式强制修改和控制。
image: {
name: "图片",
componentsProps: {
width: "160px",
height: "120px",
accept: "image",
maxSize: "50",
single: true
},
colSpan: 7.4,
rules: [{ required: true, message: "请选择图片" }],
placeholder: "请选择图片",
type: "Image",
label: "图片"
},
比如这里我们配置colSpan: 7.4 就比原来的列宽控制精确.那么 我们在列宽计算时可以这样计算。
:style="{
width: i.colSpan && i.colSpan != 24 ? `calc(100% / 24 * ${i.colSpan})` : '100%'
}"
如果有动态内容,我们也可以通过自定义表单内容排列实现,轻松排版。
比如有动态列表内容添加,需要在某一个部分,动态插入多个表单元素分为一组,可以插入多个组,并且可以删除,这时候我们只需要在配置文件内配置类型为list,然后单独渲染这个list, 实现。只需要保证数据产生出来是二个层级即可。
content: {
name: "内容",
showName: true,
list: {
rules: [
{ required: true, message: "内容不能为空" },
{ type: "limit", max: 6, message: "最多6篇" }
],
showLabel: false,
label: "论文内容",
options: {
type: {
label: "论文类型",
placeholder: "请输入论文类型",
colSpan: 24,
rules: [{ required: true, message: "请输入论文类型" }],
type: "Input"
},
title: {
label: "论文标题",
placeholder: "请输入论文标题",
colSpan: 24,
rules: [{ required: true, message: "请输入论文标题" }],
type: "Input"
},
},
colSpan: 24,
type: "List"
}
}
以上配置,就可以根据type为list 单独去渲染一个list区域,并通过options去读取渲染表单项,并关联hu据即可。
关联数据以及校验
校验时候,我们首先配置rules,关联校验的数据,以及如何实现如何触发校验。
配置文件里面我们已经配置了rules,但是这里面不一定是默认的校验规则,所以需要自己去 然后我们通过解析规则,然后手动再次生成校验规则。
:rules="[...customRules(i.options[okey].rules)]"
:name="[key, k, index, okey]"
通过rules实现绑定校验规则,通过name实现绑定层级数据,实现数据校验。
因为组件嵌套结构的关系,我们不可能在当前的页面直接通过按钮来实现表单提交校验,所以根据页面嵌套关系,我们需要通过ref向外暴露校验方法,实现校验以及去掉校验。
1.1 向外暴露整体校验
const formValidate = () => {
const validateRes = formRef.value.validate();
// 把错误消息传入自定义组件内部
return validateRes;
};
1.2 校验单独字段
// 校验单独字段
const validateFieldByField = (fieldName) => {
if (formRef.value) {
formRef.value.validateFields([fieldName]);
}
};
1.3 清除字段校验
formRef.value && formRef.value.clearValidate([[key, k]]);
灵活使用以上方法,可以实现对自定义扩展的表单项进行校验和清除校验。
保存机制
保存这里有个至关重要的问题,就是数据是双向邦定的,即父组件把数据传给内部表单渲染的组件,表单组件双向绑定到接受的到数据上(接受后,存在自己的组件状态内,监听组件内数据变化,再更新到父组件)这种设计模式,是不行的,因为及其影响性能,特别是动态增加的数据,原因是我们可能在监听时是深度监听,然后是监听到变化之后,emits到父组件,父组件数据变化后又通知到子组件,这里面如果会陷入渲染的死循环,或者说在数据量和结构比较深的时候,就会造成内存溢出(我这里有一个出现一个,就是每次根据输入的数据type字段要进行分组)。所以父组件和子组件维护的数据要解耦,即父组件只传递初始化数据,给子组件,子组件接受数据后,自己维护自己的内部数据,再数据变化时,只做emits事件。但不提交数据,父组件接受到数据之后通过ref到子组件内部取数据。
然后再每次接收到emits事件之后,做保存操作(草稿),而不是定时器去做保存。