通过一个vue+elementUI的小实例来讲解一下它们是如何使用的

本文通过一个实例介绍如何在Vue项目中使用ElementUI实现动态表单验证和模态框功能。涉及组件包括el-dialog、el-tabs,详细解释了动态表单验证的处理方式,以及如何重写组件样式。文章还讨论了子组件与父组件间的交互,以及如何优化弹窗性能。
摘要由CSDN通过智能技术生成

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

  对于熟练的人来说,实现其实很简单,但是对于没有经验的人来说,如果按照官网给的那些简单实例来做,你会发现,出现一些奇怪的问题,诸如,文本框不能编辑内容,表单验证无效等。感觉elementUI官网的示例太过于粗浅,无法适应实际工作中的许多需求场景。

  界面效果如下图所示:

  分析:用到的组件: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>

重写elementUI组件样式,可以使用/deep/ 进行样式穿透覆写。

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

 el-form中不指定验证规则,而是在el-form-item中指定,如下:
:prop="`list.${rowIndex}.${fieldArr[2*index+index+1]}`" :rules="rules.numberRule"
表单数据ruleForm中要对数据进行初始化,否则会无法自动识别数据变化,建议采用深拷贝的形式
考虑到冷站和末端这两个组件中的代码可以复用,抽取公共js文件set-mixin.js,然后通过mixins引入,这个类似于组合,还有一种继承是通过extends来实现。
分析界面虽然是动态的,但是总共只有几种类型,分别是: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: {
    alarmTmplData: {
      handler(val) {
        console.log("showAlarmSetWin cold :>> ", val);
        if (val) {
          this.initData(1);
        }

         else{            this.$refs[“ruleForm”].resetFields();         }

      },
deep:true, 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"
           
  • 22
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

java阿南

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值