需求:点击一个按钮,弹出一个模态框,这个模态框有两个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. 从0开始学自定义View -1

    PS:好久没有写博客了,之前的东西有所忘记,百度一下竟然查到了自己的写过的博客,访问量还可以,一开始的写博客的初衷是把自己不会的记录下来,现在没想到也有博友会关注我,这就给了我动力,工作之余把零零碎碎 ...

  2. WPF客户端自动升级

    实现原理:通过一个辅助程序(更新程序.exe)比较本地版本号和服务器的版本,若服务器版本新则通过更新程序.exe下载服务器上资源(我是把最新的文件压缩成zip放到服务器上)到本地进行替换. 服务器放置 ...

  3. CC2530入门

    一.简介 单片机(MCU)就是一个将微型计算机系统制作到里面的集成电路芯片. 微控制器的基本结构:内核+外设.内核通过寄存器控制外设:外设通过中断系统通知内核:内核与外设之间通过总线传输数据.地址及控 ...

  4. (一只小白)对private,final关键字的一些认知

    1.private: private是私有的意思,在Java中可以用来修饰类里面的成员变量或者成员方法(注:不能修饰一个类,因为一个类如果外部无法访问的话,面向对象的编程思想将毫无意义),顾名思义,被 ...

  5. 带你看看Java的锁(三)-CountDownLatch和CyclicBarrier

    带你看看Java中的锁CountDownLatch和CyclicBarrier 前言 基本介绍 使用和区别 核心源码分析 总结 前言 Java JUC包中的文章已经写了好几篇了,首先我花了5篇文章从源 ...

  6. Android 电池管理系统架构总结 Android power and battery management architecture summaries

    文章目录 1 整体架构 2 设计构架 2.1 driver 2.1.1 Charger.ko 2.1.2 Battery.ko 2.2 power supply 2.2.1 基础架构 2.2.2 代码 ...

  7. [hdu5445 Food Problem]多重背包

    题意:一堆食物,有价值.空间.数量三种属性,一些卡车,有空间,价格,数量三种属性.求最少的钱(不超过50000)买卡车装下价值大于等于给定价值的食物,食物可以拆开来放. 思路:这题的关键是给定的条件: ...

  8. vscode调试webpack的启动和打包部署过程,nodejs调试

    launch.json ``` {   // 使用 IntelliSense 了解相关属性.    // 悬停以查看现有属性的描述.   // 欲了解更多信息,请访问: https://go.micr ...

  9. c#与js客户端之间相互传值

    RegisterStartupScript(key, script) RegisterClientScriptBlock(key, script) 第一个参数 key 是插入的客户端脚本的唯一标识符. ...

  10. Shell脚本关于循环的一些总结

    不管是哪一门计算机语言,循环都是不可绕开的一个话题,Shell 当然也不是例外.下面总结一些 Shell 脚本里常用的循环相关的知识点,新手朋友可以参考. for 循环 Shell 脚本里最简单的循环 ...