需求:点击一个按钮,弹出一个模态框,这个模态框有两个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. awk调用date命令

    创建文件date.awk: $ == { cmd = "\"" while (cmd | getline line) { print line } close(cmd) ...

  2. python地图投影转换

    一.投影包osr与proj4的使用 1.osr投影转换示例 from osgeo import osr,ogr#定义投影#wgs84source=osr.SpatialReference()sourc ...

  3. 【Hadoop离线基础总结】oozie调度MapReduce任务

    目录 1.准备MR执行的数据 2.执行官方测试案例 3.准备我们调度的资源 4.修改配置文件 5.上传调度任务到hdfs对应目录 6.执行调度任务 1.准备MR执行的数据 MR的程序可以是自己写的,也 ...

  4. MongoDB最佳安全实践

    在前文[15分钟从零开始搭建支持10w+用户的生产环境(二)]中提了一句MongoDB的安全,有小伙伴留心了,在公众号后台问.所以今天专门开个文,写一下关于MongoDB的安全. 一.我的一次Mong ...

  5. STM32 Cube之旅-尝试新的开发方式

    尝试使用Cube进行一些开发学习,这里对此做一个梗概,先有一个全面的了解. 文章目录 Cube全家桶 CubeMX CubeIDE CubeProg 结语 Cube全家桶 曾几何时,ST刚推出Cube ...

  6. MYSQL 日月周季年分组

    首先准备几条测试数据 DROP TABLE IF EXISTS `test`;CREATE TABLE `test` ( `n_id` int(11) DEFAULT NULL, `d_created ...

  7. JS实现手机号码中间4位变星号

    这个问题,我们可以用截取字符串解决,以下我列出2种方法,小伙伴们可以根据自己的需要选择哦: ● 1,substring()方法用于提取字符串中介于两个指定下标之间的字符. '; //该号码是乱打出来的 ...

  8. uCOS2014.1.10

    uC/OS-Ⅱ任务的结构有两种:一种是无限循环结构:另一种是只执行一次的程序结构.若采用只执行一次的程序结构,就要用任务删除函数来实现. uC/OS-Ⅱ进行任务的管理是从调用启动函数OSStart() ...

  9. Android将库导入到build.gradle

    如图

  10. Lottery

    0x01 修改金币到8位,才能买东西 robots.txt中发现.git泄露 下载附件,得到源码 审计api.php 我们传入的值与随机生成的值进行比较, 按照相同的个数,得到不同的钱 if($num ...