前述
在个人博客网站中,为了避免token过期、页面意外关闭等问题,导致的已写完的博客被清空的问题,添加了草稿箱自动保存功能。
本文的实现基于Vue3与Element Plus。
一、基本思路
1.1 思路
由于主要目的是保存最新的博客内容,防止已完成的内容意外丢失,因此采用浏览器的本地存储,只对最新的博客内容进行保存,不传递到数据库保存。
主要思路为添加监听事件,当0.5s后仍没有内容或标题更新,则将当前的内容与标题保存至本地存储。并且在进入写博客页面时进行检测,如果草稿箱内不为空,则提示用户是否需要恢复。
1.2 代码实现
1.2.1 检测草稿箱内容
// 检查草稿箱是否为空
let checkDrafts = function checkDrafts() {
if (localStorage.getItem('draft') !== '' || localStorage.getItem('title') !== '') {
recover()
}
}
// 提示用户是否需要恢复
let recover = function recover() {
ElNotification({
title: '是否从草稿箱恢复内容',
dangerouslyUseHTMLString: true,
message: '<button class="el-button el-button--primary" id="recovery">恢复</button>',
type: 'info',
duration: 0,
})
}
1.2.2 自动保存
// 自动保存功能
let autoSave = function autoSave() {
saveContent.value = '正在将文章保存至草稿箱...'
localStorage.setItem('draft', submitForm.content)
localStorage.setItem('title', submitForm.title)
setTimeout(() => {
saveContent.value = '文章保存成功!'
setTimeout(() => {
saveContent.value = '文章将自动保存至草稿箱'
}, 1000)
}, 1000)
}
// 0.5s无任何更新后自动保存
let timer
let resetAutoSave = function resetAutoSave() {
clearTimeout(timer)
timer = setTimeout(autoSave, 500)
}
// 通过watch监听内容,进行保存
watch(() => [submitForm.content, submitForm.title], resetAutoSave)
二、其他问题
2.1 事件绑定
2.1.1 直接在渲染时进行绑定
采用ElNotification进行提醒,虽然ElNotification支持内容块内渲染HTML元素,但直接绑定@click(<button @click="loadSave"></button>)时,并不能正常生效,点击事件不能绑定到元素上。
参照element UI Notification通知上添加按钮和点击事件进行实现时,或许是由于Element Plus相较于Element UI做了更改,通过createElement(h)动态渲染元素后,添加的绑定事件并未生效。
2.1.2 采用ElNotification的API,绑定点击事件
ElNotification支持绑定点击事件,但通过此方法绑定的点击事件,点击ElNotification除关闭按钮外的任何一处都有效果,并不能实现只在点击恢复按钮时才触发的要求。
2.1.3 手动绑定事件
因此考虑采取先在ElNotification中渲染出button元素,再手动绑定点击事件。
// 通过ID获取元素后进行绑定
let getRecoverButton = function getRecoverButton() {
let theButton = document.getElementById('recovery')
theButton.onclick = loadDraft
}
2.2 绑定问题
在最开始的方法中,通过h函数渲染绑定时,页面加载后未点击恢复按钮,就直接加载了草稿箱内的内容。原因是在
h(
"button",
{
on: {
click: loadSave(),
},
},
"恢复"
),
中的click中,传递的是loadSave(),调用了函数,而非loadSave函数引用。
2.3 未解决的获取问题
最开始的获取考虑采用ref进行元素获取:
message:'<button class="el-button el-button--primary" ref="recovery">恢复</button>'
let recovery = ref(null)
但在onMounted生命周期中打印recover.vlaue时,获取的内容为null,猜测可能是因为ElNotification在源码中是通过异步渲染实现的,因此考虑了参照之前代码高亮博客中的解决方法。
watch(recoverButton, () => {
nextTick(() => {
console.log(recovery)
})
})
但控制台内最终没有任何输出,因此最后采用了通过ID获取元素并绑定的方法。