通过一个vue+elementUI的小实例来讲解一下它们是如何使用的
需求:点击一个按钮,弹出一个模态框,这个模态框有两个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);
}
},
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);
}
},
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,让弹窗第一次执行时也加载数据。
为了防止同一时间多次点击操作按钮“确定”,可以给按钮加上loading
通过一个vue+elementUI的小实例来讲解一下它们是如何使用的的更多相关文章
- 一个简单的Android小实例
原文:一个简单的Android小实例 一.配置环境 1.下载intellij idea15 2.安装Android SDK,通过Android SDK管理器安装或卸载Android平台 3.安装J ...
- 一个简单的Android小实例分享,包含recycleView与recyclerView嵌套
先上图: 1.首页 2.第二页 3.第三页 项目目录: 代码不多,本人太懒,就不贴了 项目地址:
- Vue + Element-ui实现后台管理系统(4)---封装一个ECharts组件的一点思路
封装一个ECharts组件的一点思路 有关后台管理系统之前写过三遍博客,看这篇之前最好先看下这三篇博客.另外这里只展示关键部分代码,项目代码放在github上: mall-manage-system ...
- 前端框架之Vue(1)-第一个Vue实例
vue官方文档 知识储备 es6语法补充 let 使用 var 声明的变量的作用域是全局. { var a = 1; } console.info(a); 例1: var arr = []; for ...
- VueX(vue状态管理)简单小实例
VueX:状态管理 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. 核心模块:State. ...
- vue3官网介绍,安装,创建一个vue实例
前言:这一章主要是vue的介绍.安装.以及如何创建一个vue实例. 一.vue介绍 vue3中文官网:建议先自己看官网. https://v3.cn.vuejs.org/ vue是渐进式框架,渐进式指 ...
- Entity Framework 的小实例:在项目中添加一个实体类,并做插入操作
Entity Framework 的小实例:在项目中添加一个实体类,并做插入操作 1>. 创建一个控制台程序2>. 添加一个 ADO.NET实体数据模型,选择对应的数据库与表(Studen ...
- vue.js开发环境搭建以及创建一个vue实例
Vue.js 是一套构建用户界面的渐进式框架.Vue 只关注视图层, 采用自底向上增量开发的设计.Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件. 在使用 vue.js ...
- 创建第一个vue实例
一.vue安装与下载 1. 官网下载 下载地址 选择开发版本 2. 打开sublime,新建vue文件夹,将下载好的代码vue.js放入vue文件夹中. 3. 新建index.html文件,在hea ...
随机推荐
- Shell脚本(五)函数
总结下shell中的函数用法 #!/bin/bash function add_v1() { echo "call function add" } function add_v2( ...
- spring cloud系列教程第一篇-介绍
spring cloud系列教程第一篇-介绍 前言: 现在Java招聘中最常见的是会微服务开发,微服务已经在国内火了几年了,而且也成了趋势了.那么,微服务只是指spring boot吗?当然不是了,微 ...
- 还在用迭代器处理集合吗?试试Stream,真香
前言 上一篇博客一文带你深入了解 Lambda 表达式和方法引用我给大家介绍了 Java8 函数式特性中的 Lambda,这篇文章我将继续讨论 stream 流的用法 声明:本文首发于博客园,作者:后 ...
- java结合email实现自动推送
1.获取表中最后一条数据 public static String demo() throws SQLException { String sql = "select * FROM baox ...
- 自动化测试po模式是什么?自动化测试po分层如何实现?-附详细源码
一.什么是PO模式 全称:page object model 简称:POM/PO PO模式最核心的思想是分层,实现松耦合!实现脚本重复使用,实现脚本易维护性! 主要分三层: 1.基础层BaseP ...
- mysql 库表整体相关查询
select table_schema,table_name from information_schema.columns where column_name = '字段名'; 查询某张表有几条记录 ...
- SpringMVC 拦截返回值,并自定义
有关取代mvc:annotation-driven使用自定义配置请看: http://blog.csdn.net/cml_blog/article/details/45222431 1.在项目开发中, ...
- Spring Boot 之 Spring Batch 批处理实践
实践内容 从 MariaDB 一张表内读 10 万条记录,经处理后写到 MongoDB . 具体实现 1.新建 Spring Boot 应用,依赖如下: <!-- Web 应用 --> & ...
- 记一条distinct 语句的优化。
语句是这条 SELECT DISTINCT bank, account FROM sdb_payments WHERE status="succ": status 上有索引,但不是 ...
- iterm 分屏切换快捷键与配色设置
(1)快捷键设置 ⌘ + d: 垂直分屏, ⌘ + shift + d: 水平分屏. ⌘ + ]和⌘ + [在最近使用的分屏直接切换. ⌘ + opt + 方向键切换到指定位置的分屏. ⌘ + 数字: ...