动态生成二级联动且数据过滤的vue element UI实现的带校验的一小块表单

又是一个令人头疼的前端需求

在同事的帮助下实现了这个功能,但是非常繁琐,如果你实现写不出来,可以借鉴这个方法,但是你要是有时间可以自己写,建议看一下https://blog.youkuaiyun.com/ClamJ092/article/details/103183703我的这篇文章,找一下思路,但是没有那么多时间了,所以只能冗余的实现这个需求,以后有时间了(不)可(可)以(能)优化一下。

看一下效果
在这里插入图片描述在这里插入图片描述就是页面加载显示一组二级联动,点击添加按钮,再添加一组二级联动,并且后边多了一个删除按钮,如果只有一组二级联动的情况下,不显示删除按钮。
然后二级联动的数据,每次选择软件的时候,如果软件名字变了,版本要清空,并且加载新的版本数据源。

下边这段话,等你先实现出来再回头看:
如果已经选择了软件A,那么在下一组软件框选择的时候,要不能排除软件A了。这里有一个坑,就是你去先添加几组二级联动的时候,再去选择了软件A,就不会再检测数组变化,所以下边依然可以选择软件A,或者你选过了之后,把软件A 移除了,但是由于下边的选框数据没有更新,所以即使你移除了软件A,但是其他选框还是没有软件A的数据。
反正专业测试去测试的时候,会发现很多小问题,但是已经改进了,不过我觉得还是用监听+隐藏实现比较好。(无代码无真相)
再有就是验证,动态生成的选框也好,输入框也好,还有这个复杂的二级联动也好,都有一个校验得名字和实际的名字必须保持一致的问题,所以不要瞎命名。

下边上一下代码

<div class="block-wrapper">
        <div class="block-content">
          <el-row v-for="(softItem, index) in postForm.softwareList" :key="index" type="flex">
            <el-form-item
              label="软件:"
              :prop="'softwareList.' + index +'.softwareName'"
              :rules="[
                { required: true, message: '请选择软件', trigger: 'change' }
              ]"
            >
              <!--一级菜单-->
              <el-select v-model="softItem.softwareName" placeholder="选择软件" clearable style="width: 200px;" @change="getVersionList($event, index)" @focus="openSelect($event,index)">
                <el-option v-for="(item,index2) in softItem.optionList" :key="index2" :value="item.softwareName" />
              </el-select>
            </el-form-item>
            <!--二级菜单-->
            <el-form-item
              label="软件版本:"
              :prop="'softwareList.' + index +'.softwareVersion'"
              :rules="[
                { required: true, message: '请选择软件版本', trigger: 'change'}
              ]"
            >
              <el-select v-model="softItem.softwareVersion" placeholder="选择软件版本" clearable style="width: 200px;" @change="getSoftwareListChanged">
                <el-option v-for="version in softItem.versionList" :key="version.id" :value="version.softwareVersion" :label="version.softwareVersion" />
              </el-select>
            </el-form-item>
            <el-form-item v-show="postForm.softwareList.length > 1">
              <i class="el-icon-delete" style="font-size: 22px; margin-left: 20px; margin-top: 8px" @click="deleteSoft(index)" />
            </el-form-item>
          </el-row>
          <el-row>
            <el-form-item>
              <el-button type="primary" @click="addSoft">添加软件</el-button>
            </el-form-item>
          </el-row>
        </div>
      </div>
postForm: {
        softwareList: [],
        //这个由于我要只传输ID,所以必须要把ID存起来给后边,所以上边的softwareList没有用,只是用来校验的
        ids: []
      },
      // 软件名称选项
      softOptions: [],
     
  created() {
    // 获取软件级联结果集
    this.getSoftOptions()
  },

这里我的数据结构是 二级联动的结构,因为当时没有想到好的解决办法,所以只能允许数据不用必须加载最新的,就保证你刷新页面是有那一批数据就可以了

在这里插入图片描述

getSoftOptions() {
      getSoftwareList().then(response => {
        this.softOptions = response.data
        // 将表单选项 存进postForm 
        this.postForm.softwareList.push({ 'optionList': this.softOptions })
      }).catch((err) => {
        if (err.status !== '-1') {
          this.$message({
            message: err.msg,
            type: 'error',
            duration: 3 * 1000
          })
        }
      })
    },
    getSoftwareListChanged() {
      this.$forceUpdate()
    },
    openSelect($event, index) {
      var selectSoftwareList = this.postForm.softwareList.map(m => m.softwareName).filter(m => m !== this.postForm.softwareList[index].softwareName)
      var allOptions = Object.assign(this.postForm.softwareList[index].optionList)
      selectSoftwareList.forEach(m => {
        allOptions = allOptions.filter(n => n.softwareName !== m)
      })
      this.postForm.softwareList[index].optionList = allOptions
    },
    getVersionList($event, index) {
      if ((this.postForm.softwareList[index].softwareName) !== '') {
        for (let i = 0; i < this.softOptions.length; i++) {
          if (this.softOptions[i].softwareName === this.postForm.softwareList[index].softwareName) {
            const currSoftList = this.postForm.softwareList[index]
            currSoftList.versionList = this.softOptions[i].versionList
            currSoftList.softwareVersion = ''
            this.listLoading = false
            Vue.set(this.postForm.softwareList, index, JSON.parse(JSON.stringify(currSoftList)))
            break
          } else {
            continue
          }
        }
      } else {
        this.postForm.softwareList[index].softwareVersion = ''
        this.softOptions.versionList = []
      }
      EvenBus.$emit('ddd', this.postForm.softwareList[index].softwareName)
      let softOptionsTemp = this.softOptions
      for (let x = 0; x < this.postForm.softwareList.length; x++) {
        for (let i = 0; i < this.postForm.softwareList.length; i++) {
          if (x === i) {
            continue
          }
          softOptionsTemp = softOptionsTemp.filter(item => item.softwareName !== this.postForm.softwareList[i].softwareName)
        }
        const currSoftList = this.postForm.softwareList[x]
        currSoftList.optionList = softOptionsTemp
        Vue.set(this.postForm.softwareList, x, currSoftList)
      }
    },
    addSoft() {
      const softOptionsTemp = this.softOptions
      // for (var i = 0; i < this.postForm.softwareList.length; i++) {
      //   softOptionsTemp = softOptionsTemp.filter(item => item.softwareName !== this.postForm.softwareList[i].softwareName)
      // }
      this.postForm.softwareList.push({ 'optionList': softOptionsTemp })
    },
    deleteSoft(index) {
      this.postForm.softwareList.splice(index, 1)
    },
    dispose() {
      // 处理软件id
      var arr = []
      this.postForm.softwareList.forEach(function(software) {
        return software.versionList.find(function(v) {
          if (v.softwareVersion === software.softwareVersion) {
            arr.push(v.id)
          }
        })
      })
      this.postForm.ids = arr
      // 之前想把数据塞进list后端再取,但是因为数组长度变化,走到这一步的时候会多出来一组二级联动框,所以就冗余了一下,又加了个ids,自己同时写前后端就是好,爱咋写咋写
      // var arr = []
      // this.postForm.softwareList.forEach(function(item) {
      //   arr.push({ 'softwareName': item.softwareName, 'softwareVersion': item.softwareVersion })
      // })
      // arr.push({ 'ids': ids })
      // this.postForm.softwareList = arr
    },
    createData() {
      var vm = this
      this.$forceUpdate()
      this.$refs.postForm.validate(valid => {
        if (valid) {
          this.dispose()
          vm.listLoading = true
          saveTask(this.postForm).then(response => {
            vm.$message({
              message: response.msg,
              type: 'success',
              duration: 2000
            })
            this.reload()
            setTimeout(function() {
              vm.listLoading = false
              vm.$router.push({
                name: 'TaskList'
              })
            }, 2 * 1000)
          }).catch((err) => {
            if (err.status !== '-1') {
              vm.$message({
                message: err.msg,
                type: 'error',
                duration: 3 * 1000
              })
            }
          })
          vm.listLoading = false
        } else {
          // this.$message({
          //   message: '表单数据填写不正确',
          //   type: 'warning',
          //   duration: 3 * 1000
          // })
          return false
        }
      })
      // 这里是因为填了数据,但是不选版本,先提交表单但是会提示软件版本为空,想的解决办法,但是没有用,后来发现是原来是校验检测名字跟实际的名字不一样。
      // this.$refs['postForm'].clearValidate()
    },

这是新建 几乎99%没毛病了,但是编辑的时候,提交表单还是有问题,就是校验检测名字跟实际的名字不一样,导致校验不通过。我还在想办法。。再补充。
不过如果你真的有时间 强烈不建议这样写,因为数据结构超级乱。还是用监听+隐藏解决吧

编辑的问题解决了,我以为是动态监测的问题,但是同事说是数据存的位置的问题

 <div class="block-wrapper">
          <div class="block-content">
            <el-row v-for="(softItem, index) in postForm.softwareList" :key="index" type="flex">
              <el-form-item
                label="选择软件:"
                :prop="'softwareList.' + index +'.softwareName'"
                :rules="[
                  { required: true, message: '请选择软件', trigger: 'change' }
                ]"
              >
                <!--一级菜单 -->
                <el-select v-model="softItem.softwareName" placeholder="选择软件" clearable style="width: 200px;" :disabled="readonlyYES" @change="getVersionList($event, index)" @focus="openSelect($event,index)">
                  <el-option v-for="(item,index2) in softItem.optionList" :key="index2" :value="item.softwareName" />
                </el-select>
              </el-form-item>
              <!--二级菜单-->
              <el-form-item
                label="软件版本:"
                :prop="'softwareList.' + index +'.softwareVersion'"
                :rules="[
                  { required: true, message: '请选择软件版本', trigger: 'change' }
                ]"
              >
                <el-select v-model="softItem.softwareVersion" placeholder="选择软件版本" :disabled="readonlyYES" clearable style="width: 200px;" @change="getSoftwareListChanged">
                  <el-option v-for="version in softItem.versionList" :key="version.id" :value="version.softwareVersion" :label="version.softwareVersion" />
                </el-select>
              </el-form-item>
              <el-form-item v-show="postForm.softwareList.length > 1">
                <i class="el-icon-delete" style="font-size: 22px; margin-left: 20px; margin-top: 8px" @click="deleteSoft(index)" />
              </el-form-item>
            </el-row>
            <el-row>
              <el-form-item>
                <el-button v-if="!readonlyYES" type="primary" style="margin-left: 5px; width: 128.36px" @click="addSoft">添加软件</el-button>
              </el-form-item>
            </el-row>
          </div>
        </div>
 // 将软件名称选项 放进这里
    // this.postForm.softwareList.push({ 'optionList': this.softOptions })
    getSoftwareListChanged() {
      this.$forceUpdate()
    },
    // 这是什么方法
    openSelect($event, index) {
      var selectSoftwareList = this.postForm.softwareList.map(m => m.softwareName).filter(m => m !== this.postForm.softwareList[index].softwareName)
      var allOptions = Object.assign(this.postForm.softwareList[index].optionList)
      selectSoftwareList.forEach(m => {
        allOptions = allOptions.filter(n => n.softwareName !== m)
      })
      this.postForm.softwareList[index].optionList = allOptions
    },
    // 拆分软件版本 根据名称调用
    getVersionList($event, index) {
      for (let i = 0; i < this.softOptions.length; i++) {
        if (this.softOptions[i].softwareName === this.postForm.softwareList[index].softwareName) {
          const currSoftList = this.postForm.softwareList[index]
          currSoftList.versionList = this.softOptions[i].versionList
          currSoftList.softwareVersion = ''
          Vue.set(this.postForm.softwareList, index, JSON.parse(JSON.stringify(currSoftList)))
          // this.postForm.softwareList[index].softwareVersion = ''
          break
        }
      }
      var softOptionsTemp = this.softOptions
      for (let x = 0; x < this.postForm.softwareList.length; x++) {
        for (let i = 0; i < this.postForm.softwareList.length; i++) {
          if (x === i) {
            continue
          }
          softOptionsTemp = softOptionsTemp.filter(item => item.softwareName !== this.postForm.softwareList[i].softwareName)
        }
        const currSoftList = this.postForm.softwareList[x]
        currSoftList.optionList = softOptionsTemp
        Vue.set(this.postForm.softwareList, x, currSoftList)
      }
    },
    // openSelect($event, index) {
    //   console.log(2)
    //   // console.log(this.postForm.softwareList)
    //   var selectSoftwareList = this.postForm.softwareList.map(m => m.softwareName).filter(m => m !== this.postForm.softwareList[index].softwareName)
    //   var allOptions = Object.assign(this.postForm.softwareList[index].optionList)
    //   selectSoftwareList.forEach(m => {
    //     allOptions = allOptions.filter(n => n.softwareName !== m)
    //   })
    //   this.postForm.softwareList[index].optionList = allOptions
    // },
    addSoft() {
      var softOptionsTemp = this.softOptions
      for (var i = 0; i < this.postForm.softwareList.length; i++) {
        softOptionsTemp = softOptionsTemp.filter(item => item.softwareName !== this.postForm.softwareList[i].softwareName)
      }
      this.postForm.softwareList.push({ 'optionList': softOptionsTemp })
    },
    deleteSoft(index) {
      this.postForm.softwareList.splice(index, 1)
    },
    dispose() {
      // 处理软件id
      var arr = []
      this.postForm.softwareList.forEach(function(software) {
        return software.versionList.find(function(v) {
          if (v.softwareVersion === software.softwareVersion) {
            arr.push(v.id)
          }
        })
      })
      this.postForm.ids = arr
    },
     disSoft(data) {
      if (data.length === 0) {
        this.postForm.softwareList.push({ 'optionList': this.softOptions })
      } else {
        this.postForm.softwareList = data
        this.postForm.softwareList.forEach(item => {
          item.softwareVersion = item.versionList[0].softwareVersion
          // item.versionList.forEach(items => {
          //   this.postForm.softwareList.softwareVersion = items.softwareVersion
          //   console.log(items.softwareVersion)
          //   console.log(this.postForm.softwareList.softwareVersion)
          // })
        })
      }
      // for (let i = 0; i < this.postForm.softwareList.length; i++) {
      //   console.log(this.postForm.softwareList[i])
      //   for (let j = 0; j < this.postForm.softwareList[i].versionList.length; j++) {
      //     this.postForm.softwareList[i].softwareVersion = this.versionList[j].softwareVersion
      //   }
      // }
    },
    // setTagsViewTitle() {
    //   const title = '编辑子任务'
    //   const route = Object.assign({}, this.tempRoute, { title: `${title}` })
    //   console.log(route)
    //   this.$store.dispatch('updateVisitedView', route)
    // },
    // 基于已选择的软件信息构建数据结构
    buildOptions() {
      var softOptionsTemp = this.softOptions
      for (let x = 0; x < this.postForm.softwareList.length; x++) {
        for (let i = 0; i < this.postForm.softwareList.length; i++) {
          if (x === i) {
            continue
          }
          softOptionsTemp = softOptionsTemp.filter(item => item.softwareName !== this.postForm.softwareList[i].softwareName)
        }
        const currSoftList = this.postForm.softwareList[x]
        currSoftList.optionList = softOptionsTemp
        Vue.set(this.postForm.softwareList, x, currSoftList)
      }
    },
    // 基于已选择的软件信息构建软件版本数据结构
    buildVersion() {
      var softOptions = this.softOptions
      for (let x = 0; x < this.postForm.softwareList.length; x++) {
        var softOptionsTemp = softOptions.filter(item => item.softwareName === this.postForm.softwareList[x].softwareName)
        const currSoftList = this.postForm.softwareList[x]
        currSoftList.versionList = softOptionsTemp[0].versionList
        Vue.set(this.postForm.softwareList, x, currSoftList)
      }
    },
    // 处理响应数据
    processing(res) {
    this.softOptions = res.data.softOptions
     this.disSoft(res.data.softwareList)
this.buildOptions()
this.buildVersion()
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值