hookehuyr

fix: 添加组件卸载时的资源清理逻辑

在TEditor、MarqueeField、VideoField组件和主视图页面中添加onUnmounted钩子
清理tinymce实例、定时器和视频播放器资源,防止内存泄漏
1 <!-- 1 <!--
2 * @Date: 2022-08-29 14:31:20 2 * @Date: 2022-08-29 14:31:20
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2022-11-23 10:49:41 4 + * @LastEditTime: 2025-09-30 22:13:39
5 * @FilePath: /data-table/src/components/MarqueeField/index.vue 5 * @FilePath: /data-table/src/components/MarqueeField/index.vue
6 * @Description: 跑马灯控件 6 * @Description: 跑马灯控件
7 --> 7 -->
...@@ -32,6 +32,14 @@ onMounted(() => { ...@@ -32,6 +32,14 @@ onMounted(() => {
32 ScrollUp(); 32 ScrollUp();
33 }); 33 });
34 34
35 +onUnmounted(() => {
36 + // 清理定时器
37 + if (intNum.value) {
38 + clearInterval(intNum.value);
39 + intNum.value = null;
40 + }
41 +});
42 +
35 const top = computed(() => { 43 const top = computed(() => {
36 return -activeIndex.value * 30 + "px"; 44 return -activeIndex.value * 30 + "px";
37 }); 45 });
......
...@@ -346,6 +346,13 @@ onMounted(() => { ...@@ -346,6 +346,13 @@ onMounted(() => {
346 // tinymce.init({}); 346 // tinymce.init({});
347 }); 347 });
348 348
349 +onUnmounted(() => {
350 + // 清理tinymce实例
351 + if (tinymce.activeEditor) {
352 + tinymce.activeEditor.destroy();
353 + }
354 +});
355 +
349 // 设置值 356 // 设置值
350 const handleSetContent = (content) => { 357 const handleSetContent = (content) => {
351 tinymce.activeEditor.setContent(content); 358 tinymce.activeEditor.setContent(content);
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
21 */ 21 */
22 import "mui-player/dist/mui-player.min.css"; 22 import "mui-player/dist/mui-player.min.css";
23 import MuiPlayer from "mui-player"; 23 import MuiPlayer from "mui-player";
24 -import { onMounted } from "vue"; 24 +import { onMounted, onUnmounted } from "vue";
25 import { useEventListener } from "@/composables"; 25 import { useEventListener } from "@/composables";
26 26
27 // 视频基础属性 27 // 视频基础属性
...@@ -31,8 +31,18 @@ const props = defineProps({ ...@@ -31,8 +31,18 @@ const props = defineProps({
31 // 视频播放事件回调 31 // 视频播放事件回调
32 const emit = defineEmits(["active"]); 32 const emit = defineEmits(["active"]);
33 let video = null; 33 let video = null;
34 +let muiPlayerInstance = null;
35 +
36 +/**
37 + * 视频播放事件处理函数
38 + */
39 +const handleVideoPlay = () => {
40 + props.item.value = { key: "video", value: "play" };
41 + emit("active", props.item.value);
42 +};
43 +
34 onMounted(() => { 44 onMounted(() => {
35 - const mp = new MuiPlayer({ 45 + muiPlayerInstance = new MuiPlayer({
36 container: "#mui-player", 46 container: "#mui-player",
37 // title: props.item.component_props.title, 47 // title: props.item.component_props.title,
38 src: props.item.component_props.src, 48 src: props.item.component_props.src,
...@@ -45,12 +55,9 @@ onMounted(() => { ...@@ -45,12 +55,9 @@ onMounted(() => {
45 { attrKey: "x5-video-player-type", attrValue: "h5-page" }, 55 { attrKey: "x5-video-player-type", attrValue: "h5-page" },
46 ], 56 ],
47 }); 57 });
48 - video = mp.video(); 58 + video = muiPlayerInstance.video();
49 //视频播放事件监听 59 //视频播放事件监听
50 - video.addEventListener("play", function () { 60 + video.addEventListener("play", handleVideoPlay);
51 - props.item.value = { key: "video", value: "play" };
52 - emit("active", props.item.value);
53 - });
54 // 配置16:9高度比 61 // 配置16:9高度比
55 const width = document.getElementById("mui-player").clientWidth; 62 const width = document.getElementById("mui-player").clientWidth;
56 const height = (width * 9) / 16; 63 const height = (width * 9) / 16;
...@@ -58,7 +65,16 @@ onMounted(() => { ...@@ -58,7 +65,16 @@ onMounted(() => {
58 }); 65 });
59 66
60 onUnmounted(() => { 67 onUnmounted(() => {
61 - video.removeEventListener("play", function () {}); 68 + // 移除事件监听器
69 + if (video) {
70 + video.removeEventListener("play", handleVideoPlay);
71 + }
72 + // 销毁MuiPlayer实例
73 + if (muiPlayerInstance) {
74 + muiPlayerInstance.destroy();
75 + muiPlayerInstance = null;
76 + }
77 + video = null;
62 }); 78 });
63 </script> 79 </script>
64 80
......
...@@ -387,6 +387,9 @@ const collapseRef = ref(null); ...@@ -387,6 +387,9 @@ const collapseRef = ref(null);
387 387
388 const show_loading = ref(false); 388 const show_loading = ref(false);
389 389
390 +// 定时器ID,用于清理轮询
391 +let subscribeCheckInterval = null;
392 +
390 onMounted(async () => { 393 onMounted(async () => {
391 // 显示加载动画 394 // 显示加载动画
392 show_loading.value = true; 395 show_loading.value = true;
...@@ -615,6 +618,14 @@ onMounted(async () => { ...@@ -615,6 +618,14 @@ onMounted(async () => {
615 }, false); 618 }, false);
616 }); 619 });
617 620
621 +onUnmounted(() => {
622 + // 清理定时器
623 + if (subscribeCheckInterval) {
624 + clearInterval(subscribeCheckInterval);
625 + subscribeCheckInterval = null;
626 + }
627 +});
628 +
618 // 自定义失焦操作 629 // 自定义失焦操作
619 // const onBlur = async (item) => { 630 // const onBlur = async (item) => {
620 // console.warn(item); 631 // console.warn(item);
...@@ -637,7 +648,11 @@ onMounted(async () => { ...@@ -637,7 +648,11 @@ onMounted(async () => {
637 // 打开轮询用户是否关注 648 // 打开轮询用户是否关注
638 const onTap = () => { 649 const onTap = () => {
639 if (localStorage.getItem('weixin_subscribe') === '0') { 650 if (localStorage.getItem('weixin_subscribe') === '0') {
640 - setInterval(() => { 651 + // 清理之前的定时器(如果存在)
652 + if (subscribeCheckInterval) {
653 + clearInterval(subscribeCheckInterval);
654 + }
655 + subscribeCheckInterval = setInterval(() => {
641 checkUserSubscribe() 656 checkUserSubscribe()
642 }, 1000); 657 }, 1000);
643 } 658 }
...@@ -650,6 +665,11 @@ const checkUserSubscribe = () => { ...@@ -650,6 +665,11 @@ const checkUserSubscribe = () => {
650 // 标记用户已关注 665 // 标记用户已关注
651 localStorage.setItem('weixin_subscribe', 1); 666 localStorage.setItem('weixin_subscribe', 1);
652 show_qrcode.value = false; 667 show_qrcode.value = false;
668 + // 清理定时器
669 + if (subscribeCheckInterval) {
670 + clearInterval(subscribeCheckInterval);
671 + subscribeCheckInterval = null;
672 + }
653 } 673 }
654 // 凭密码填写设置 674 // 凭密码填写设置
655 if (formSetting.value.mmtx_enable) { 675 if (formSetting.value.mmtx_enable) {
......