需求:点击一个按钮,弹出一个模态框,这个模态框有两个tab,tab中是各种报警条件,这些报警条件是从数据库中动态取出的,数据库中数据变更后,这个界面也要变更,我们可以查看和编辑这些报警条件。底部“确定”按钮点击的时候,会同时将这两个tab中的内容都报错到数据库中去,数据录入要验证输入的格式。

  对于熟练的人来说,实现其实很简单,但是对于没有经验的人来说,如果按照官网给的那些简单实例来做,你会发现,出现一些奇怪的问题,诸如,文本框不能编辑内容,表单验证无效等。

  界面效果如下图所示:

  分析:用到的组件:el-dialog、el-tabs

  AlarmSet.vue代码:

<template>
<div>
<div class="alarm-set" v-loading="winLoading">
<el-tabs v-model="activeName" type="border-card" v-if="alarmTmplData.length>0">
<el-tab-pane label="制冷站" name="coldSet">
<ColdSet
ref="coldSet"
:alarmTmplData="alarmTmplData"
@onSubmit="coldSetSummit"
:showAlarmSetWin.sync="showAlarmSetWin"
></ColdSet>
</el-tab-pane>
<el-tab-pane label="末端" name="endSet">
<EndSet
ref="endSet"
:alarmTmplData="alarmTmplData"
@onSubmit="endSetSummit"
:showAlarmSetWin.sync="showAlarmSetWin"
></EndSet>
</el-tab-pane>
</el-tabs>
</div>
<div slot="footer" class="dialog-footer">
<div style="display: inline-block">
<el-button type="primary" @click="onSubmit" :loading="btnLoading">确 定</el-button>
<el-button @click="isHide">取 消</el-button>
</div>
</div>
</div>
</template> <script>
import ColdSet from "./ColdSet";
import EndSet from "./EndSet";
import mixinsOption from "@/mixins/mixin-options";
import { alarmService } from "@/services/cold-station-service";
// import { alarmConditionData } from "@/mock/json.js";
export default {
mixins: [mixinsOption],
props: {
showAlarmSetWin: {
type: Boolean,
default: false
},
alarmTmpl: {
type: Object,
default: {}
}
},
components: {
ColdSet,
EndSet
},
data() {
return {
alarmConditionData: [], //报警条件数据
activeName: "coldSet",
alarmTmplData: [],
coldConditionData: [], //冷站报警条件数据
endConditionData: [], //末端报警条件数据
isColdValid: false,
isEndValid: false,
btnLoading: false
};
},
watch: {
showAlarmSetWin: {
handler(val) {
console.log("showAlarmSetWin", val);
if (val) {
this.initData();
}
},
immediate: true
}
},
methods: {
//初始化数据
initData() {
this.$store.commit("base/setWinLoading", true);
console.log("initData");
alarmService
.getConditionList({
groupNumber: this.groupNumber,
projectNumber: this.projectNumber
})
.then(res => {
if (res.code === 200) {
this.alarmConditionData = res.data;
this.createAlarmTmplData(res.data);
}
this.$store.commit("base/setWinLoading", false);
});
},
//构造报警模板数据
createAlarmTmplData(conditionData) {
let res = [];
this.alarmTmplData = this.alarmTmpl.data;
if (this.alarmTmpl) {
this.alarmTmplData.forEach(n => {
// debugger;
n.descr = eval(n.descr);
let item = conditionData.find(m => m.tempId == n.id);
if (item) {
n["alarmLevel"] = item.alarmLevel;
n["suggestion"] = item.suggestion;
n["firstVal"] = item.firstVal;
n["secondVal"] = item.secondVal;
n["fourthVal"] = item.fourthVal;
n["thirdVal"] = item.thirdVal;
n["status"] = item.status;
}
});
}
// console.log("this.alarmTmplData :>> ", this.alarmTmplData);
},
//确定操作
onSubmit() {
this.$refs["coldSet"].onSubmit();
this.$refs["endSet"].onSubmit();
if (this.isColdValid && this.isEndValid) {
this.btnLoading = true;
let list = this.coldConditionData
.concat(this.endConditionData)
.map(m => {
return {
tempId: m.id,
alarmLevel: m.alarmLevel,
firstVal: m.firstVal,
secondVal: m.secondVal,
thirdVal: m.thirdVal,
fourthVal: m.fourthVal,
status: m.status,
suggestion: m.suggestion
};
}); alarmService
.batchEdit({
projectNumber: this.projectNumber,
groupNumber: this.groupNumber,
list: list
})
.then(res => {
if (res.code === 200) {
this.$message({
message: "操作成功!",
type: "success",
duration: this.$baseConfig.messageDuration
});
}
this.btnLoading = false;
})
.catch(() => {
this.btnLoading = false;
});
}
},
coldSetSummit(val, isValid) {
if (isValid) {
this.isColdValid = isValid;
this.coldConditionData = val;
}
},
endSetSummit(val, isValid) {
if (isValid) {
this.isEndValid = isValid;
this.endConditionData = val;
}
},
//取消
isHide() {
this.$emit("update:showAlarmSetWin", false);
}
}
};
</script> <style lang="scss" scoped>
.alarm-set {
height: 600px;
/deep/ .el-tabs--border-card {
height: 100%;
}
/deep/ .el-tabs__content {
height: calc(100% - 60px);
}
}
</style>

关于表单验证:由于是动态生成的表单,所以不能按照官网提供的示例来做。

 el-form中不指定验证规则,而是在el-form-item中指定,如下:
:prop="`list.${rowIndex}.${fieldArr[2*index+index+1]}`"
:rules="rules.numberRule"
表单数据ruleForm中药对数据进行初始化,否则会无法自动识别数据变化,建议采用深拷贝的形式
考虑到冷站和末端这两个组件中的代码可以复用,抽取公共js文件set-mixin.js
分析界面虽然是动态的,但是总共只有几种类型,分别是:1个文本框,2个文本框,没有文本框。他们都带有建议信息这一行,所以可以用几个v-if来区分。
import { alarmLevelOptions, fieldArr } from '@/enum/alarm-enum.js';
import Regexps from '@/utils/regexp.js';
import mixinsOption from '@/mixins/mixin-options';
export default {
props: {
alarmTmplData: {
type: Array,
default: () => {
return [];
},
},
showAlarmSetWin: {
type: Boolean,
default: false,
},
},
mixins: [mixinsOption],
data() {
return {
levelOptions: alarmLevelOptions(),
ruleForm: {
list: [],
},
rules: {
numberRule: [
{
pattern: Regexps.commonNumber,
message: '仅支持3位数和带1位小数',
trigger: 'blur',
},
],
suggestion: [
{ max: 10, message: '长度不能超过10个字符', trigger: 'blur' },
],
},
fieldArr,
tmplData: [],
};
},
computed: {
activeNames() {
let activeNames = this.tmplData
.filter((f) => f.descParamType != 0)
.map((n) => {
return n.id;
});
console.log('activeNames :>> ', activeNames);
return activeNames;
},
},
methods: {
initData(type) {
console.log('initData', type);
if (this.alarmTmplData.length > 0) {
this.tmplData = this.alarmTmplData.filter((n) => n.sys == type);
this.ruleForm.list = JSON.parse(JSON.stringify(this.tmplData));
// console.log('条件设置initData :>> ', this.ruleForm.list);
}
},
},
};

ColdSet.vue代码:

<template>
<div>
<el-form :model="ruleForm" ref="ruleForm">
<el-collapse v-model="activeNames">
<el-collapse-item :name="item.id" v-for="(item,rowIndex) in ruleForm.list" :key="item.id">
<template slot="title">
<div class="header">
<el-checkbox v-model="item.status" :true-label="0" :false-label="1">{{item.name}}</el-checkbox>
<el-select v-model="item.alarmLevel" size="small">
<el-option
v-for="item in levelOptions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</div>
</template>
<div class="content vertical">
<div class="row one" v-if="item.descParamType==1">
<div class="item" v-for="(subItem,index) in item.descr" :key="index">
<label>{{subItem}}</label>
<el-form-item
label="大于"
:prop="`list.${rowIndex}.${fieldArr[index]}`"
:rules="rules.numberRule"
>
<el-input v-model="item[`${fieldArr[index]}`]" size="small"></el-input>
</el-form-item>
</div>
</div>
<template v-if="item.descParamType==2">
<div class="row two" v-for="(subItem,index) in item.descr" :key="index">
<div class="item">
<label>{{subItem}}</label>
<el-form-item
label="大于"
:prop="`list.${rowIndex}.${fieldArr[2*index+index]}`"
:rules="rules.numberRule"
>
<el-input
v-model="item[`${fieldArr[2*index+index]}`]"
size="small"
></el-input>
</el-form-item>
<el-form-item
label="或小于"
:prop="`list.${rowIndex}.${fieldArr[2*index+index+1]}`"
:rules="rules.numberRule"
>
<el-input
v-model="item[`${fieldArr[2*index+index+1]}`]"
size="small"
></el-input>
</el-form-item>
</div>
</div>
</template> <div class="row one">
<el-form-item
label="建议信息"
:prop="`list.${rowIndex}.suggestion`"
:rules="rules.suggestion"
>
<el-input
v-model="item.suggestion"
class="max-width"
size="small"
placeholder="请尽快处理"
></el-input>
</el-form-item>
</div>
</div>
</el-collapse-item>
</el-collapse>
</el-form>
</div>
</template> <script>
import { alarmLevelOptions, fieldArr } from "@/enum/alarm-enum.js";
import Regexps from "@/utils/regexp.js";
import { validateVal } from "@/utils/validate-utils.js";
import { alarmService } from "@/services/cold-station-service";
import setMixin from "./set-mixin";
export default {
mixins: [setMixin],
watch: {
showAlarmSetWin: {
handler(val) {
console.log("showAlarmSetWin cold :>> ", val);
if (val) {
this.initData(1);
}
         else{
           this.$refs["ruleForm"].resetFields();
        }
      },
immediate: true
}
},
methods: {
onSubmit() {
console.log("冷站确定 :>> ");
this.$refs["ruleForm"].validate(valid => {
if (valid) {
console.log("验证成功");
this.$emit("onSubmit", this.ruleForm.list, true);
}
});
}
}
};
</script> <style lang="scss" scoped>
@import "./set.scss";
</style>

EndSet.vue:

<template>
<div>
<el-form :model="ruleForm" ref="ruleForm">
<el-collapse v-model="activeNames">
<el-collapse-item :name="item.id" v-for="(item,rowIndex) in ruleForm.list" :key="item.id">
<template slot="title">
<div class="header">
<el-checkbox v-model="item.status" :true-label="0" :false-label="1">{{item.name}}</el-checkbox>
<el-select v-model="item.alarmLevel" size="small">
<el-option
v-for="item in levelOptions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</div>
</template>
<div class="content vertical">
<div class="row two" v-if="item.descParamType==1">
<div class="item" v-for="(subItem,index) in item.descr" :key="index">
<label>{{subItem}}</label>
<el-form-item
label="大于"
:prop="`list.${rowIndex}.${fieldArr[index]}`"
:rules="rules.numberRule"
v-if="index==0"
>
<el-input v-model="item[fieldArr[index]]" size="small"></el-input>
</el-form-item>
</div>
</div>
<div class="row two" v-if="item.descParamType==2">
<div class="item" v-for="(subItem,index) in item.descr" :key="index">
<label>{{subItem}}</label>
<el-form-item
label="大于"
:prop="`list.${rowIndex}.${fieldArr[2*index+index]}`"
:rules="rules.numberRule"
>
<el-input v-model="item[fieldArr[2*index+index]]" size="small"></el-input>
</el-form-item>
<el-form-item
label="或小于"
:prop="`list.${rowIndex}.${fieldArr[2*index+index+1]}`"
:rules="rules.numberRule"
>
<el-input v-model="item[fieldArr[2*index+index+1]]" size="small"></el-input>
</el-form-item>
</div>
</div>
<div class="row two" v-if="item.descParamType==3">
<div class="item">
<el-form-item
:label="subItem"
:prop="`list.${rowIndex}.${fieldArr[index]}`"
:rules="rules.numberRule"
v-for="(subItem,index) in item.descr"
:key="index"
>
<el-input v-model="item[fieldArr[index]]" size="small"></el-input>
</el-form-item>
</div>
</div>
<template v-if="item.descParamType==4">
<div class="row one" v-for="(subItem,index) in item.descr" :key="index">
<div class="item">{{subItem}}</div>
<div class="item">
<el-form-item
:label="index==0?'小于':'大于'"
:prop="`list.${rowIndex}.${fieldArr[index]}`"
:rules="rules.numberRule"
>
<el-input v-model="item[fieldArr[index]]" size="small"></el-input>
</el-form-item>
</div>
</div>
</template>
<!-- <div class="row multi-row" v-if="item.descParamType==4">
multi-item
</div>-->
<div class="row one">
<el-form-item
label="建议信息"
:prop="`list.${rowIndex}.suggestion`"
:rules="rules.suggestion"
>
<el-input
v-model="item.suggestion"
class="max-width"
size="small"
placeholder="请尽快处理"
></el-input>
</el-form-item>
</div>
</div>
</el-collapse-item>
</el-collapse>
</el-form>
</div>
</template> <script>
import setMixin from "./set-mixin";
import { alarmService } from "@/services/cold-station-service";
export default {
mixins: [setMixin],
watch: {
showAlarmSetWin: {
handler(val) {
console.log("showAlarmSetWin end:>> ", val);
if (val) {
this.initData(2);
}
         else{
           this.$refs["ruleForm"].resetFields();
        }
      },
immediate: true
}
},
methods: {
onSubmit() {
console.log("末端确定 :>> ");
this.$refs["ruleForm"].validate(valid => {
if (valid) {
console.log("验证成功");
this.$emit("onSubmit", this.ruleForm.list, true);
}
});
}
}
};
</script> <style lang="scss" scoped>
@import "./set.scss";
</style>

由于要两个tab中都验证通过时,才提交表单,所以两个表单都要验证,只有都验证通过时在提交表单,提交表单之前,要合并表单数据再统一提交。父组件调用子组件的方法 this.$refs["coldSet"].onSubmit();

考虑到弹窗组件的性能问题,我们可以通过将显示标识以 :showAlarmSetWin.sync="showAlarmSetWin"这样的形式传递给子组件,子组件监听showAlarmSetWin,当弹窗显示时,加载数据并初始化,并设置属性:immediate: true,让弹窗第一次执行时也加载数据。

当窗体隐藏时,重置表单:

this.$refs["ruleForm"].resetFields();

为了防止同一时间多次点击操作按钮“确定”,可以给按钮加上loading

通过一个vue+elementUI的小实例来讲解一下它们是如何使用的的更多相关文章

  1. 一个简单的Android小实例

    原文:一个简单的Android小实例 一.配置环境 1.下载intellij idea15 2.安装Android SDK,通过Android SDK管理器安装或卸载Android平台   3.安装J ...

  2. 一个简单的Android小实例分享,包含recycleView与recyclerView嵌套

    先上图: 1.首页 2.第二页 3.第三页 项目目录: 代码不多,本人太懒,就不贴了 项目地址:

  3. Vue + Element-ui实现后台管理系统(4)---封装一个ECharts组件的一点思路

    封装一个ECharts组件的一点思路 有关后台管理系统之前写过三遍博客,看这篇之前最好先看下这三篇博客.另外这里只展示关键部分代码,项目代码放在github上: mall-manage-system ...

  4. 前端框架之Vue(1)-第一个Vue实例

    vue官方文档 知识储备 es6语法补充 let 使用 var 声明的变量的作用域是全局. { var a = 1; } console.info(a); 例1: var arr = []; for ...

  5. VueX(vue状态管理)简单小实例

    VueX:状态管理 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. 核心模块:State. ...

  6. vue3官网介绍,安装,创建一个vue实例

    前言:这一章主要是vue的介绍.安装.以及如何创建一个vue实例. 一.vue介绍 vue3中文官网:建议先自己看官网. https://v3.cn.vuejs.org/ vue是渐进式框架,渐进式指 ...

  7. Entity Framework 的小实例:在项目中添加一个实体类,并做插入操作

    Entity Framework 的小实例:在项目中添加一个实体类,并做插入操作 1>. 创建一个控制台程序2>. 添加一个 ADO.NET实体数据模型,选择对应的数据库与表(Studen ...

  8. vue.js开发环境搭建以及创建一个vue实例

    Vue.js 是一套构建用户界面的渐进式框架.Vue 只关注视图层, 采用自底向上增量开发的设计.Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件. 在使用 vue.js ...

  9. 创建第一个vue实例

    一.vue安装与下载 1. 官网下载  下载地址 选择开发版本 2. 打开sublime,新建vue文件夹,将下载好的代码vue.js放入vue文件夹中. 3. 新建index.html文件,在hea ...

随机推荐

  1. golang之array

    golang使用array表示固定大小的数组,使用slice表示动态数组. package main import "fmt" func main() { var a = [5]i ...

  2. MongoDB 部署以及操作

    目录 1.MongoDB简介 2.MongoDB优势 3.MongoDB安装 3.MongoDB用户管理 3.1.Mongodb创建超级管理员 3.2.MongoDB创建读写用户 3.3.Moongo ...

  3. 记忆化搜索 E - Loppinha, the boy who likes sopinha Gym - 101875E

    E - Loppinha, the boy who likes sopinha Gym - 101875E 这个题目是一个dp,这个应该很容易看出来,但是对于状态的定义其实有点难去想, 看了题解dp[ ...

  4. java并发之线程安全问题

    并发(concurrency)一个并不陌生的词,简单来说,就是cpu在同一时刻执行多个任务. 而Java并发则由多线程实现的. 在jvm的世界里,线程就像不相干的平行空间,串行在虚拟机中.(当然这是比 ...

  5. Spring Cloud Alibaba系列(二)nacos作为服务配置中心

    Nacos 提供用于存储配置和其他元数据的 key/value 存储,为分布式系统中的外部化配置提供服务器端和客户端支持.使用 Spring Cloud Alibaba Nacos Config,您可 ...

  6. node常用插件使用

    1.nodemon 用于热更新,随时监控文件的变化 安装npm i -g nodemon 使用nodemon index.js 2.nvm nvm用于nodejs版本管理,我们在开发过程中,不同的项目 ...

  7. 绝对一个月精通vue

    马上从vue-cli4练手,要不然,学几年,你也不懂组件式开发,不懂VUEX,不懂路由, 也许你会说你懂, 麻烦你花一个月学vue-cli4以一个完整购物商城来练手,   一个月后,如果还觉得我错,我 ...

  8. Excel函数有门槛,是编程

    Excel的公式体系,最简单的就是输入“=1+1”.“=2*3”.看起来没有门槛,但实质上是函数式编程,Range写Formula,Power Query写M语言,VBA里写Function.通过菜单 ...

  9. 简述异步编程&Promise&异步函数

    前言:文章由本人在学习之余总结巩固思路,不足之前还请指出. 一.异步编程 首先我们先简单来回顾一下同步API和异步API的概念 1.同步API:只有当前的API执行完成之前,才会执行下一个API 例: ...

  10. 如何将Altera官方提供的CADENCE.OLB应用于altium Designer中