vue超大表单页面设计思路(产品发布)

99 阅读1分钟

一、功能描述

  1. 产品发布页面,整个页面是一个大的表单,所以拆分成一个个子组件,每个组件都是一个form
  2. 点击页面底部的提交按钮时,需要能校验出来每个子表单,并且滚动条滚动到校验失败的那个表单位置上
  3. 特殊表单的校验给出message提示

动画.gif

二、结构分析

每个组件都是一个el-form,并且绑定上ref属性,组件内定义一个validate方法,使用element-ui表单给的validate方法来进行校验

image.png

组件内validate方法:

    validate() {
      return new Promise((res, rej) => {
        this.$refs.ruleFormRef.validate((valid) => {
          if (valid) {
            res(valid)
          } else {
            rej(valid)
          }
        })
      })
    },

父组件中,我这里使用了vue的内置组件component,也给绑定上ref属性

image.png

在点击提交按钮时,使用Promise.all方法,它会等待所有的子组件校验完,再给出最后的校验结果

    // 确认提交
    async handleSubmit(done) {
      try {
        await Promise.all(this.$refs.comRef.map((ref) => ref?.validate()))
        console.log('校验通过')
      } catch (err) {
        done()
        this.$nextTick(() => {
          this.elFormErrorScrollIntoView('.is-error')
        })
      }
    },

当校验不通过时,el-form会给el-form-item元素添加上is-error类名,使用scrollIntoView方法滚动到这个类名的位置上

    elFormErrorScrollIntoView(tag) {
      // 获取第一个校验错误的元素
      const element = document.querySelectorAll(tag)[0]
      console.log('报错的元素', element)
      // 滚动到错误元素对应位置
      element.scrollIntoView({ behavior: 'smooth', block: 'center' })
    },

三、特殊的表单如何校验

比如说规格信息中的规格图和印刷区域维护中的印刷底图都是必填的,但是我无法通过el-form给出必填的提示,这里可以使用message抛出提示(其实表格内的表单也可以给出红色字体提示,参考:juejin.cn/post/727669… 这里是给出思路,万一哪天就是很难给出红色字体提示了,可以使用这个方法)

image.png

从上至下,依次可以给出message提示,并且可以滚动到对应的位置上:

动画.gif

SpecInfo组件中的validate方法需要进行改造,判断是否有规格图没有上传,如果有,则给没有上传规格图的容器添加上is-error类名,并且调用rej使其可以被父组件中的try catch捕获到

    validate() {
      return new Promise((res, rej) => {
      this.$refs.ruleFormRef.validate((valid) => {
        if (valid) {
          // 是否有未上传的规格图,true=有未上传 false=全部已上传
          const flag = this.specInfo.specsDTOList.some((item) => !item.imageUrl)
          const elements = this.$el.querySelectorAll('.erptable-upload-image--wrapper')
          if (flag) {
            elements.forEach((element) => {
              if (!element.querySelector('.el-image')) {
                element.classList.add('is-error') // 添加上类名,页面会自动滚动到未上传规格图的位置上
              }
            })
            rej('请选择规格图')
          } else {
            elements.forEach((element) => {
              element.classList.remove('is-error')
            })
            res(valid)
          }
        } else {
          rej(valid)
        }
      })
    },

父组件中,catch中,err就是调用rej传递的内容,可以使用message抛出提示

image.png

印刷面图片未上传,在PrintArea组件中也是类似的处理,如此,便可以实现此类需求。

此外,这个页面还实现了锚点导航,可以监听页面滚动使对应的导航title高亮,点击title滚动到对应的页面位置上,不过篇幅较大不利于理解,在另一篇博客中:juejin.cn/post/741411…