需求:点击一个按钮,弹出一个模态框,这个模态框有两个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. System.Linq.Dynamic字符串转委托

    以前一直想着有没有一个方法能够把字符串直接转化成函数的,刚好有需求就找了下,还真有. 微软地址:https://docs.microsoft.com/en-us/previous-versions/b ...

  2. 使用jQuery完成课工场论坛列表

    1.点击我要发帖 2.显示出form表单,然后我们填入标题和选择板块 3.点击发布,隐藏表单,发帖列表中出现随机头像,刚才填入的标题和板块显示在列表中,其中还显示出了发布消息的时间 4.再一次的点击我 ...

  3. 第3章:关系数据库标准语言 SQL

    目录 第3章:关系数据库标准语言 SQL 3.1.SQL概述 3.1.1.历史 3.3.2.SQL语言的功能 3.3.3.SQL的特点 3.3.4.基本概念 3.2.学生-课程数据库 3.3.数据定义 ...

  4. spring学习笔记(九)事务学习(上)

    前述 ​ 这段时间在工作中碰到一个事务相关的问题.先说下这个问题的场景,我们是一个商城项目,正在开发优惠券模块,现在有一个需求是需要批量领取优惠券,而且在领券时,其中一张领取失败不能影响其他符合要求的 ...

  5. ES[7.6.x]学习笔记(八)数据的增删改

    在前面几节的内容中,我们学习索引.字段映射.分析器等,这些都是使用ES的基础,就像在数据库中创建表一样,基础工作做好以后,我们就要真正的使用它了,这一节我们要看看怎么向索引里写入数据.修改数据.删除数 ...

  6. 将csv文件导入sql数据库

    有一个csv文件需要导入到Sql数据库中,其格式为 “adb”,"dds","sdf" “adb”,"dds","sdf" ...

  7. python学习第七天--文件系统常用模块os,os.path,pickle

    模块是一个可用代码段的打包,后缀名为py,可被别的程序引入#使用import OS模块:operting system操作系统#import os os.chdir(path) 改变当前工作目录 os ...

  8. Jmeter-Throughput Controller 吞吐量控制器

    比如在压测是时候,我设置了100个线程组,循环2次,那么我想根据吞吐量进行并发请求,这时候可以用到这个吞吐量控制器 PercentExecutions:按执行次数的百分比来计算执行次数,Through ...

  9. shell 光标处理快捷键

    Ctrl+左右键 单词之间跳转Ctrl+a跳到本行的行首, Ctrl+e则跳到页尾. Ctrl+u删除当前光标前面的文字 ctrl+k-删除当前光标后面的文字 Ctrl+w和Alt+d-对于当前的单词 ...

  10. Windows基础学习

    0x01 常用的端口 HTTP协议代理服务器常用端口号:80/8080/3128/8081/9098SOCKS代理协议服务器常用端口号:1080FTP(文件传输)协议代理服务器常用端口号:21Teln ...