文章目录
- 一、前言
- 二、实现步骤
- 1. 第一步: 引入 PendingActions 插件
- 2. 第二步:注册事件
- 3. 第三步:点击保存按钮时,控制状态变化
- 三、测试效果和细节
- 四、总结
一、前言
在上一篇文章中 ck-editor5的研究 (5):优化-页面离开时提醒保存,顺便了解一下 Editor的生命周期 和 6大编辑器类型 ,我们对离开页面时进行了优化。
但是每次刷新页面,都会有弹窗警告。这篇文章,我们进一步优化,只有当数据发生变化、正在保存中时,刷新页面才进行提示。
实现的效果图大致如下:
二、实现步骤
大致分成了 3 个步骤,我们仍然使用上一篇文章的目录结构
1. 第一步: 引入 PendingActions 插件
这个插件在 @ckeditor/ckeditor5-core 里面,需要先安装这个依赖
pnpm add @ckeditor/ckeditor5-core@37.1.0
可以看到这个 插件的文档,然后在 ckeditor5.ts 中使用插件:
2. 第二步:注册事件
在demo5/index.vue中,编辑器初始化完成后,注册状态变更事件,这里用到了一个新接口 instance.plugin.get 方法(获取某个插件):
3. 第三步:点击保存按钮时,控制状态变化
在点击保存按钮时,控制 按钮可点击状态 和 是否保存中状态,同时在 window 对象的 beforeunload 事件中判断状态,决定是否弹窗提示,完整代码如下:
<template><div class="space-y-4"><h1 class="text-xl font-bold">demo5: 优化-页面离开时提醒用户保存信息</h1><!-- TODO 测试控制面板 --><div class="flex gap-2"><buttonid="save"@click="handleSaveButton"class="text-white cursor-pointer rounded border-none bg-blue-500 px-4 py-2 text-[#fff] outline-none":class="{ active: !isDirty, saving: isSaving }">{{ !isDirty ? '数据没变化,无需保存' : isSaving ? '保存中...' : '点击保存' }}</button><div class="text-gray-500 flex items-center text-sm">{{ isSaving ? '保存中......刷新页面有离开提示' : '非保存中,刷新页面不提示' }}</div></div><!-- 编辑器组件 --><ClientOnly><CkEditor5 @ready="handleEditorReady" /></ClientOnly></div>
</template><script setup lang="ts">
import type MyClassicEditor from '@/components/ck/editor5/ckeditor5';let instance: MyClassicEditor | null = null;
const isDirty = ref(false);
const isSaving = ref(false);const handleEditorReady = (editor: MyClassicEditor) => {console.log('editor :>> ', editor);instance = editor;initStatusChangesEvent();
};/*** 初始化2个状态改变的事件 `change:hasAny` 和 `change:data`*/
function initStatusChangesEvent() {// 获取插件const peddingActionPlugin = instance?.plugins.get('PendingActions');// console.log('peddingActionPlugin :>> ', peddingActionPlugin);// 此插件自带一个 `change:hasAny` 事件可以监听是否有动作正在进行中peddingActionPlugin?.on('change:hasAny', () => {updateStatus();});// 编辑器实例对象, 监听 `change:data`(内容变更) 事件, 内容有改变时,才可以点击保存按钮instance?.model.document.on('change:data', () => {isDirty.value = true;updateStatus();});
}/*** 使用`pendingActions.hasAny` 判断是否正在保存中*/
function updateStatus() {if (instance?.plugins.get('PendingActions').hasAny) {isSaving.value = true;} else {isSaving.value = false;}
}/*** 点击保存按钮时,控制状态变化*/
function handleSaveButton(e: Event) {console.log('handleSaveButton');e.preventDefault();const data = instance?.getData();const pendingActions = instance?.plugins.get('PendingActions');// 添加一个保存中状态, 可以使用`pendingActions.hasAny` 判断是否保存中const action = pendingActions?.add('Saving changes');// console.log('action :>> ', action);if (!action) {return;}// 模拟保存中状态, 5秒后移除保存中状态setTimeout(() => {pendingActions?.remove(action);// 如果数据没有变化, 则设置为未修改状态if (data === instance?.getData()) {isDirty.value = false;}updateStatus();}, 5000);
}/*** 注册页面卸载事件, 判断是否有动作正在进行中。决定是否弹窗提醒*/
useEventListener(window, 'beforeunload', (event: BeforeUnloadEvent) => {const pendingActions = instance?.plugins.get('PendingActions');// console.log('pendingActions :>> ', pendingActions);if (pendingActions?.hasAny) {event.preventDefault();}
});
</script><style lang="less" scoped>
// 样式
.active {background-color: #007bff;opacity: 0.5;cursor: not-allowed;pointer-events: none; // 禁止元素触发点击事件
}
.saving {background-color: #007bff;opacity: 0.5;cursor: not-allowed;pointer-events: none;
}
</style>
三、测试效果和细节
在 demo5/index.vue 中测试该组件,可以看到效果:
可以看到:当数据没有变化时,不需要保存,因此按钮不可点击; 当数据发生变化时,我们通过点击触发手动保存动作(也可以用定时器每隔一段时间自动保存),假如正在保存中,则刷新页面会进行提示。
四、总结
到此为止,我们算是完成了所有优化,增强了用户保存内容的体验,同时又不那么频繁触发弹窗。