问题描述

在我们做项目中,会遇到这样的问题,就是在某个页面有一个form表单供用户输入填写,需求是:如果用户在表单中输入了内容,但是没有点击保存,而突然想离开这个页面了,就要提示询问是否保存,这个时候就要判断表单内容是否发生变化,并做相应的逻辑控制。本篇文章分三种情况去简述如何判断form表单是否发生变化的解决思路

情况一 判断新增页面的表单是否发生变化

先说新增页面,新增页面比较特殊,因为里面的初始值都为空,所以我们只需要去判断,变化前和变化后的form表单的值是否不为空即可

html部分

<template>
  <div id="app">
     <el-form ref="form" :model="form" label-width="80px">
      <el-form-item label="姓名">
        <el-input v-model.trim="form.name"></el-input>
      </el-form-item>
      <el-form-item label="年龄">
        <el-input v-model.trim="form.age"></el-input>
      </el-form-item>
      <el-form-item label="籍贯">
        <el-input v-model.trim="form.home"></el-input>
      </el-form-item>
    </el-form>
    <el-button @click="leave">离开</el-button>
  </div>
</template>

js部分

<script>
export default {
  name: "app",
  data() {
    return {
      /* 第一步,form对象和html中的el-form-item一一对应,这个简单常规操作
              然后因为是新增页面,所以初始值我们直接定义为空即可,一般用字符串空
            或者是null空去表示,后面判断是否发生变化也是判断是否不为空*/ 
      form:{
        name:null,
        age:"",
        home:null
      }
    };
  },
  methods: {
    // 假设用户点击了按钮准备离开当前页了,然后去做判断
    leave(){
      /* 第二步,定义一个初始标识为0,遍历form对象,此时的对象就三种情况,null或空字符串
              或者有输入内容值。如果遍历获取的属性值为null或空字符串就让num不变,如果不为null
                不为空字符串就说明用户输入内容了,就把标识num加上一。最终去判断这个num的值
                如果num的值最终还是0,说明用户始终没有输入内容,就允许用户直接离开。如果num的
                值最终大于0,就说明用户输入内容了,然后就询问用户是否要保留刚刚输入的内容。
      */ 
      let num = 0
      for (const key in this.form) {
        if(this.form[key] == ""){
          num = num + 0
        }else if(this.form[key] == null){
          num = num + 0
        }else{
          num = num + 1
        }
      }
      // 第三步,根据标识num的最终值,去做流程逻辑控制判断
      if(num > 0){
        console.log("询问是否保存当前数据")
      }else{
        console.log("允许路由跳转");
      }
    }
  },
};
</script>

情况二 判断编辑页面的表单是否发生变化

html部分

编辑页面的html部分同新增页的html部分一样

js部分

<script>
export default {
  name: "app",
  data() {
    return {
      form:{}
    };
  },
  mounted() {
    /* 第一步,因为是在编辑页,所以进入这个页面的时候,我们需要发请求,获取对应的初始数据
            这里的初始数据,一般会是一部分有值,另外一部分为空。思路是把初始值存两份,一份
            存到data中去,用于页面显示,另外一份存到本地。后面就判断form中的内容和本地存的
            初始值是否一致。一致就说明没有变化,不一致就说明变化了,说明用户输入内容了,就
            询问用户是否保存
    */ 
    let apiForm = { // 假设apiForm是我们发请求获取的数据
      name:"孙悟空",
      age:500,
      home:"" /* 小细节,如果有空值,让后端传空字符串,这里home不能用null,因为若用户输入空格或
                输入内容以后又删除掉,这里的null就会变成空字符串了,大家可以自己试试,小细节 */ 
    }
    this.form = apiForm
    sessionStorage.setItem("initForm",JSON.stringify(apiForm)) // 因为是对象,所以要转成字符串存储
  },
  methods: {
    leave(){
      /* 第二步,判断this.form和initForm是否相等,不相等就提示用户是否保存
         这里有一个细节,因为this.form和initForm都是对象,对象和对象是永远不相等的
         (对象是引用数据类型,指向的堆地址是不相等的)所以要把对象转成字符串,看是否相等
         initForm已经转成字符串了,所以转一下this.form去判断就行了
      */ 
      if(JSON.stringify(this.form) == sessionStorage.getItem("initForm")){
        console.log("表单没变化,允许离开");
      }else{
        console.log("表单变化,询问是否保存");
      }
    }
  },
};
</script>

三、使用this.$options.data()判断

this.$options.data()会存放组件最初的data值,所以用这个判断初始值,和后续值是否一致也是可以的

  data() {
    return {
      form: {
        name: "",
        region: "",
      },
    };
  },
  methods: {
    exit() {
      let initForm = JSON.stringify(this.$options.data().form);
      let afterForm = JSON.stringify(this.form);
      if (initForm == afterForm) {
        console.log("表格没变化,直接退出");
      } else {
        console.log("表格变化了,询问是否要保存?");
      }
    },
  },

另外this.$options.data()也可以重置data中的所有数据,有种页面初始化的感觉。如:Object.assign(this.$data, this.$options.data())。切记,不能直接赋值哦,不能这样写:this.$data = this.$options.data();

单独某一个form数据,就是:this.form = this.$options.data().form;

总结

如果想要全面的进行控制,可以结合vue路由的拦截钩子,beforeRouteLeave。具体情况具体分析,本篇文章只是简述了三种思路,具体怎么做还要看业务场景和需求。2021,大家共同加油


水冗水孚
1.1k 声望585 粉丝

每一个不曾起舞的日子,都是对生命的辜负