航天器达到环绕地球、脱离地球和飞出太阳系所需要的最小发射速度,分别称为第一宇宙速度(牛顿称之为环绕速度)7.9km/s、第二宇宙速度(脱离速度)11.2km/s和第三宇宙速度(太阳的逃逸速度)16.7km/s。
最近一直在忙别的事情,没有更新。接下来如果不忙的时候应该会重新巩固一下基础知识,然后再看看框架源码,研究一下DSL方案的低代码实现方式,研究一下如果实现一个web版的光影魔术手都需要那些技术点。
800多行代码的表单
说一点最近做的东西,一个相对复杂一点的表单。其原型大致如下:
如图: 该表单分三个步骤,第一步,可以为【系统】(这里为了避嫌用系统两个字代替)配置基本信息。第二步可以为【系统】添加用户信息,且可以添加多个用户,用户客户设置为默认用户,当其中一个用户为默认状态时,其他则取消默认状态,是一个互斥的关系。第三部最为复杂,存在7个配置项,7个配置项中有四个可以添加多条记录,另外三个是系统物料配置(banner图上传及详情页图片上传)其中banner图也可以上传多张。如图:
右上角的开关关闭后,卡片内容收起;右上角开关打开后,卡片内容展开;同时点击添加按钮,添加新的上传banner区域,点击删除,移除对应的banner。右上角开关逻辑适用于7个配置项,同时7个配置项中有两个配置项是数组形式,且每项配置都带同样功能的开关,合计开关共计15个。
表单校验规则
当开关关闭时,卡片内容不校验。当开关开启时,对卡片内容全部校验。
具体解决流程
对于复杂的业务,通常情况还是将其拆分成几个简单的业务组件。比如,因为该项目采用vue框架进行开发,在该表单中拆出来三个组件baseInfoForm
,userInfoForm
,ruleInfoForm
。分别写三个步骤的逻辑。将对应的表单信息baseInfo
, userInfo
,ruleInfo
存入store, 通过mapstate或computed,映射到组件内,然后绑定表单,实时更新。
表单验证部分,在对应的组件设置ref
,某些表单内容通过遍历数组对象进行渲染,设置prop=.${keyName}
,在组件上配置相应的校验规则。
表单提交时,通过this.refs[formName].validate(v=>{...})
进行校验,校验通过后,调用服务端接口进行数据提交。
一个比较直观的例子是早几年前写的:
代码语言:javascript复制<template>
<div>
<div class="funcs-box func-set"
v-for="(item, key) in actions"
:key="key">
<div class="header">
<h4 class="title">功能{{key 1}}</h4>
<div class="handle">
<Button type="error"
size="small"
@click="deleteFunc(key)"
style="float:right;">删除功能
</Button>
</div>
</div>
<Form :model="item"
:rules="ruleValidate"
:label-width="50"
style="width:300px"
ref="funcForm"
>
<FormItem prop="name"
label="名称">
<Input type="text"
v-model="item.name"
placeholder="名称" />
</FormItem>
<FormItem label="标题"
prop="title">
<Input type="text"
v-model="item.title"
placeholder="标题" />
</FormItem>
<FormItem label="类型"
prop="type">
<Select v-model="item.type"
>
<Option v-for="inner in item.typeArray"
:value="inner.value"
:key="inner.value">{{ inner.label }}</Option>
</Select>
</FormItem>
</Form>
<div v-for="(inner, index) in item.content"
class="params-item"
:key="index">
<row>
<Button type="error"
size="small"
@click="deleFuncAttr(key,index)"
style="float:right;">删除该参数
</Button>
</row>
<p class="title">参数{{index 1}}:</p>
<Form :model="inner"
:label-width="80"
:rules="innerRuleValidate"
ref="funcFormParams"
style="width:300px"
>
<FormItem label="名称"
prop="name">
<Input type="text"
v-model="inner.name"
placeholder="请输入名称" />
</FormItem>
<FormItem label="关联属性"
:label-width="80">
<Select v-model="inner.relateName"
>
<Option v-for="innerItem in associatedProperty"
:value="innerItem.value"
:key="innerItem.value">{{ innerItem.label }}
</Option>
</Select>
</FormItem>
</Form>
</div>
<row class="add-func">
<i-col :span='4'>
<Button icon="plus-round"
@click="addNewFuncParam(key)">引用属性</Button>
</i-col>
</row>
</div>
<template>
<row class="add-func">
<i-col :span='4'>
<Button icon="plus-round"
@click="addNewFunc">增加新功能</Button>
</i-col>
</row>
</template>
</div>
</template>
<script>
export default {
name: 'funcs',
props: {
actions: Array,
associatedProperty: Array
},
data() {
return {
funcs: [
{
name: '启动服务',
attrID: 'func_start',
type: '指令下发',
params: [
{
name: '启动类别',
attrID: 'start_type',
type: '整数',
length: '2',
default: '1',
required: '是'
}
]
}
],
ruleValidate: {
name: [
{
required: true,
message: '请填写英文功能名称!',
trigger: 'blur',
type: 'string',
pattern: /[a-zA-Z]/
}
],
title: [
{
required: true,
message: '请填写功能标题!',
trigger: 'blur',
type: 'string'
}
],
type: [{ required: true, message: '请选择类型!', trigger: 'change' }]
},
innerRuleValidate: {
name: [
{
required: true,
message: '请填写英文参数名称!',
trigger: 'blur',
type: 'string',
pattern: /[a-zA-Z]/
}
]
}
}
},
mounted() {
},
methods: {
addNewFunc() {
this.$store.commit('templateManage/addActions')
},
typeChange(key, index) {
this.actions[key].content[index].defaultValue = ''
},
addNewFuncParam(index) {
for (let i = 0; i < this.actions.length; i ) {
if (i === index) {
this.actions[i].content.push({
name: '',
relateName: ''
})
}
}
this.$store.commit('templateManage/setActions', this.actions)
},
deleteFunc(index) {
for (let i = 0; i < this.actions.length; i ) {
if (i === index) {
this.actions.splice(index, 1)
}
}
this.$store.commit('templateManage/setActions', this.actions)
},
deleFuncAttr(parentIndex, index) {
for (let i = 0; i < this.actions.length; i ) {
if (parentIndex === i) {
this.actions[i].content.splice(index, 1)
}
}
this.$store.commit('templateManage/setActions', this.actions)
},
checkFuncName() {
let self = this
if (this.actions.length > 0) {
this.$refs.funcForm.forEach(item => {
item.validate(valid => {
if (valid) {
self.checkFuncParams()
} else {
this.$emit('checkSuccess', false)
}
})
})
} else {
this.$emit('checkSuccess', true)
}
},
checkFuncParams() {
this.$refs.funcFormParams.forEach(item => {
item.validate(valid => {
if (valid) {
this.$emit('checkSuccess', true)
} else {
this.$emit('checkSuccess', false)
}
})
})
},
checkForm() {
return this.checkFuncName()
}
},
watch: {
actions: {
handler(curVal, oldVal) {
this.$store.commit('templateManage/setActions', curVal)
},
deep: true
}
}
}
</script>
关于表单和表单的交互
其实对于表单来说,很多时候没必要设计这么复杂,复杂的设计通常表现出来的本质是对业务的理解不够深刻。
拿上面写的那个复杂表单来说,其实也是三个功能,系统管理
,用户管理
,配置管理
,系统创建成功以后,可以给该系统配置相应的用户
及物料
,各种规则
即可。这样一来界面可能会增加一些,但是复杂度却可以降低很多。
对于表单的交互,个人的理解是复杂的表单开新界面,简单的表单直接弹窗展示
。因为对于用户来说,交互越简单越好,操作越少越好。
总结
800行代码写个表单也好,80行代码写个表单也好,只要能实现业务功能,理解业务本质,又有什么区别呢?
技术原本就是为业务服务的
。
javascript基础知识总结