Vue实现表单本地草稿功能

背景

最近做了一个Lesson Learned系统,在业务功能都完成之后,用户反响很强烈,要求实现一个草稿功能,因为表单比较大,他们怕在工作的时候,突然有什么事情耽搁,导致系统被关闭,这时候他们填写的内容功亏一篑,需要重新填写,这时候就很麻烦了,于是强烈要求实现这个功能。

当然本着打工人的原则,一开始我是拒绝的。。。,但是天大地大甲方爸爸最大,最后实在不行,就简单的做了一个草稿功能,以供他们使用。

前期准备

存储

既然简单,那么我个人认为存在本地肯定是最好的,具体存在哪里呢,

sessionStorage,明显是不能委以重任的,为什么呢?因为它会在页面关闭的时候清除缓存,这就跟需求相悖,因为突然退出,这种退出的场景肯定也包括了界面突然关闭,所以丢掉。

cookie,嗯这家伙可以用,我们还可以实现定时自动清理。

localStorage,嗯,也可以,但是不能实现自动清理。

权衡利弊之后,我随随便便就选了localStorage,为什么呢,随便选的,别问为什么,问就是随便选的。

技术栈

按照我上面的选择,肯定是学一下怎么用localStorage,它的存取和删除,这个肯定是要实现的。

然后就是Vue,我们怎么实现用本地存储去缓存草稿,当然选watch啦,因为深度监听的时候,基本所有东西都是可以缓存的。

开始开发

监听,并存储

基于以上的准备,我们此时只需要监听form的动态即可,每次更新值,form的所有值就存储进去,简直完美,可真的是这样吗?

watch: {
    form: {
      handler(newForm) {
        // this.$cache.local可以写为localStorage.setItem(draftLocalKey, JSON.stringify(newForm)), 其中draftLocalKey为当前界面的全局变量,表示存储草稿的本地存储key
        // this.$cache.local 这个方法我是若依自带的方法,最后我会贴出来
        this.$cache.local.setJSON(draftLocalKey, newForm)
      },
      deep: true
    }
  },

好的,此时我们已经迈出了一大步,实现了form值的存储。

怎么取?

漂亮,这又是一个核心点,如果存了不取,简直可恶。

什么怎么取?既然是退出,再进来,肯定要用created咯?真的吗?要不先用mounted吧,好的,那么此时我们知道了在界面dom元素绑定完成之后,调用draftLocalKey这个key的值,并识别,那不妨先写一个方法:

mounted() {
  this.loadLocalDraftData()
},
methods: {
  loadLocalDraftData() {
    const draft = this.$cache.local.getJSON(draftLocalKey)
    this.form = draft
  }
}

以上就实现了取,这时候有些用户就不开心了,为什么呢?我不一定每次都需要调用啊,天理何在?那我们使用elementUI的confirm功能给他做一个选择呗,上面代码改造如下:

mounted() {
  this.loadLocalDraftData()
},
methods: {
  loadLocalDraftData() {
    const draft = this.$cache.local.getJSON(draftLocalKey)
    
    this.$confirm('要恢复草稿吗?'), '我在问你').then(() => {
      // 同意恢复
      this.form = draft
    }).catch(() => {
      // 爷们不同意
    })
  }
}

好的,一个基础的功能实现了。

问题

为什么我什么都没存,但是每次进入的时候都会询问?

问得好!

watch在执行init的时候,除去首次监听,它自己还会发生改变,这时候watch会监听到变化,我们在watch中没有做对form默认值的控制,所以才会发生这种现象,所以,我做了一个最简单粗暴的方法,另外一般来说在提交form之后编辑不需要控制存储没所以我做了一些变更。

// 草稿本地存储key
const draftLocalKey = 'MEKTEC_CACH_LL_TEMP_DATA'
const dradtDefaultValues = '{"form":{"analysisType":"5why","layer":[],"smt":[],"lob":[],"badProject":[],"station":[],"cause":[],"influence":[]}}'


export default {
watch: {
  form: {
    handler(newForm) {
      // 只有在创建的时候才能保存草稿
      if (this.$route.query.id) return
      // 检测是否为默认状态
      if (this.validateFormIsEmpty({ form: newForm })) return

      const draft = this.$cache.local.getJSON(draftLocalKey) || {}

      draft.form = newForm
      this.$cache.local.setJSON(draftLocalKey, draft)
    },
    deep: true
  }
},
mounted() {
  this.loadLocalDraftData()
},
methods: {
  // 检测对象是否未能填写的对象
  validateFormIsEmpty(validateForm) {
    return dradtDefaultValues === JSON.stringify(validateForm)
  },
  loadLocalDraftData() {
    if (this.$route.query.id) return
    const draft = this.$cache.local.getJSON(draftLocalKey)
    // 如果没有存的时候直接忽略
    if (!draft) return
    this.$confirm('要恢复草稿吗?'), '我在问你').then(() => {
      // 同意恢复
      this.form = draft
    }).catch(() => {
      // 爷们不同意
    })
  }
}
}

简单粗暴的办法是什么呢?我做了一个全局变量,每次进入的时候检查这个静态全局变量JSON.stringify是否等于首次加载出来的form JSON.stringify后的值,这时候就可以了,我相信有更好的方法,但是这里够用,就再没用别的办法了,以上基本就算是完成了。

这时候还有个问题,那就是子列表如果也要缓存,那么我可以根据代码中的内容取去做改变,每次list更新的时候更新缓存的内容,但是这时候需要在修改、保存的时候监听。貌似json的变更在watch中监听不到。

然后初始化的时候直接调用。

最终代码如下:

// 草稿本地存储key
const draftLocalKey = 'MEKTEC_CACH_LL_TEMP_DATA'
const dradtDefaultValues = '{"form":{"analysisType":"5why","layer":[],"smt":[],"lob":[],"badProject":[],"station":[],"cause":[],"influence":[]}}'

export default {
  watch: {
    form: {
      handler(newForm) {
        // 只有在创建的时候才能保存草稿
        if (this.$route.query.id) return
        // 检测是否为默认状态
        if (this.validateFormIsEmpty({ form: newForm })) return

        const draft = this.$cache.local.getJSON(draftLocalKey) || {}

        draft.form = newForm
        this.$cache.local.setJSON(draftLocalKey, draft)
      },
      deep: true
    }
  },
  mounted() {
    this.loadLocalDraftData()
  },
  methods: {
  // 加载本地缓存的草稿内容
    loadLocalDraftData() {
      if (this.$route.query.id) return
      const draft = this.$cache.local.getJSON(draftLocalKey)

      if (!draft) return
      this.$confirm('要恢复草稿吗?'), '我在问你').then((res) => {
        this.form = draft.form
        // 设置5m1e
        if (this.$refs.edit5M1E && draft['5m1e']) {
          this.$refs.edit5M1E.tableData = draft['5m1e']
        }
        // 设置5why
        if (this.$refs.edit5Why && draft['5why']) {
          this.$refs.edit5Why.tableData = draft['5why']
        }
        // 设置5w1h
        if (this.$refs.edit5w1h && draft['5w1h']) {
          this.$refs.edit5w1h.tableData = draft['5w1h']
        }
        // 设置todolist
        if (this.$refs.editTodolist && draft['todolist']) {
          this.$refs.editTodolist.tableData = draft['todolist']
        }
        // 设置选中的审核人
        if (this.$refs.checkAuditDRI) {
          this.$refs.checkAuditDRI.setCheckedKeys(draft.approver)
        }
      }).catch(() => {
        // console.log('不加载草稿')
      })
    },
    // 检测对象是否未能填写的对象
    validateFormIsEmpty(validateForm) {
      return dradtDefaultValues === JSON.stringify(validateForm)
    },
    // 清理草稿缓存
    clearLocalDraft() {
      this.$cache.local.remove(draftLocalKey)
      this.$message.success(this.$t('baseName.operationSuccessful'))
    }
  }
}

吃饭去了,先到这里,哪里不懂问我。。。。。 bye~~~

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值