79 lines
1.7 KiB
Vue
79 lines
1.7 KiB
Vue
<script setup lang="ts">
|
|
const emit = defineEmits<{
|
|
(e: "change", changed: boolean): void;
|
|
}>();
|
|
|
|
let hideTimer: NodeJS.Timeout | null = null;
|
|
|
|
/** 是否发生变化 */
|
|
const hasChanged = ref(false);
|
|
/** 上一次的内容,用于对比变化 */
|
|
const previousContent = ref("");
|
|
/* 是否初次渲染 */
|
|
const isInitialized = ref(false);
|
|
|
|
const cellRef = useTemplateRef<HTMLElement | null>("cellRef");
|
|
|
|
const checkChange = async () => {
|
|
await nextTick();
|
|
|
|
if (!cellRef.value) return;
|
|
|
|
const currentContent = cellRef.value?.textContent?.trim() || "";
|
|
|
|
if (!isInitialized.value) {
|
|
// 首次渲染,记录原始值
|
|
previousContent.value = currentContent;
|
|
isInitialized.value = true;
|
|
hasChanged.value = false;
|
|
} else {
|
|
// 对比变化
|
|
hasChanged.value = currentContent !== previousContent.value;
|
|
emit("change", hasChanged.value);
|
|
}
|
|
};
|
|
|
|
watch(hasChanged, (newVal) => {
|
|
if (newVal) {
|
|
if (hideTimer) clearTimeout(hideTimer);
|
|
|
|
hideTimer = setTimeout(() => {
|
|
hasChanged.value = false;
|
|
emit("change", false);
|
|
previousContent.value = cellRef.value?.textContent?.trim() || "";
|
|
}, 1000);
|
|
}
|
|
});
|
|
|
|
let observer: MutationObserver | null = null;
|
|
|
|
watch(
|
|
cellRef,
|
|
(el) => {
|
|
observer?.disconnect();
|
|
|
|
if (el) {
|
|
checkChange();
|
|
|
|
observer = new MutationObserver(checkChange);
|
|
observer.observe(el, {
|
|
childList: true,
|
|
subtree: true,
|
|
characterData: true
|
|
});
|
|
}
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
</script>
|
|
|
|
<template>
|
|
<div
|
|
ref="cellRef"
|
|
class="transition-colors duration-300"
|
|
:class="{ 'bg-muted h-full w-full p-4 -my-4': hasChanged }"
|
|
>
|
|
<slot />
|
|
</div>
|
|
</template>
|