最近做了一个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~~~