Browse Source

优化富文本刷新拼音和气泡列表更新

zq 1 month ago
parent
commit
173988c09a

+ 21 - 14
src/components/RichText.vue

@@ -556,18 +556,18 @@ export default {
               this.cleanupRemovedAnnotations(editor);
             }, 500);
           });
-          // editor.on('NodeChange', function (e) {
-          //   if (
-          //     e.element &&
-          //     e.element.tagName === 'SPAN' &&
-          //     e.element.hasAttribute('data-annotation-id') &&
-          //     (!e.element.textContent || /^\s*$/.test(e.element.textContent))
-          //   ) {
-          //     const annotationId = e.element.getAttribute('data-annotation-id');
-          //     e.element.parentNode.removeChild(e.element);
-          //     this.$emit('selectContentSetMemo', null, annotationId);
-          //   }
-          // });
+          editor.on('NodeChange', (e) => {
+            if (
+              e.element &&
+              e.element.tagName === 'SPAN' &&
+              e.element.hasAttribute('data-annotation-id') &&
+              (!e.element.textContent || /^\s*$/.test(e.element.textContent))
+            ) {
+              const annotationId = e.element.getAttribute('data-annotation-id');
+              e.element.parentNode.removeChild(e.element);
+              this.$emit('selectContentSetMemo', null, annotationId);
+            }
+          });
 
           editor.on('blur', () => {
             const body = editor.getBody();
@@ -576,6 +576,7 @@ export default {
               body.setAttribute('data-mce-placeholder', this.placeholder);
             }
           });
+          let cleanupTimer = null;
           editor.on('input', () => {
             const body = editor.getBody();
             const content = editor.getContent({ format: 'text' }).trim();
@@ -584,6 +585,12 @@ export default {
             } else if (body && !content && !body.hasAttribute('data-mce-placeholder') && this.placeholder) {
               body.setAttribute('data-mce-placeholder', this.placeholder);
             }
+            //  防抖:连续输入只保留最后一次,停止500ms后执行一次清理
+            if (cleanupTimer) clearTimeout(cleanupTimer);
+            cleanupTimer = setTimeout(() => {
+              this.cleanupRemovedAnnotations(editor);
+              cleanupTimer = null;
+            }, 500);
           });
         },
         font_formats:
@@ -1334,7 +1341,7 @@ export default {
           note: '',
         };
         // console.log('初始化注释数据:', note);
-        this.$emit('selectContentSetMemo', note, noteId);
+        this.$emit('selectContentSetMemo', note);
       }
 
       // 打开弹窗
@@ -1383,7 +1390,7 @@ export default {
           dataStr: noteContent, // 兼容字段
           selectText,
         };
-        this.$emit('selectContentSetMemo', note, noteId);
+        this.$emit('selectContentSetMemo', note);
       } else {
         console.error('未找到对应的注释');
       }

+ 46 - 34
src/views/book/courseware/create/components/base/rich_text/RichText.vue

@@ -2,7 +2,7 @@
 <template>
   <ModuleBase ref="base" :type="data.type">
     <template #content>
-      <div :style="{ width: data.note_list.length > 0 ? '' : '100%' }">
+      <div v-loading="loading" :style="{ width: data.note_list.length > 0 ? '' : '100%' }">
         <RichText
           v-if="property.isGetContent"
           ref="richText"
@@ -161,6 +161,7 @@ export default {
       inited: false,
       paragraphVersion: 0,
       tempNoteData: null,
+      loading: false,
     };
   },
   computed: {
@@ -337,38 +338,45 @@ export default {
       data.is_match_annota = hasNotes; // 是否匹配注释,默认为 false
       data.annota_list = hasNotes ? this.data.note_list : [];
 
-      await PinyinBuild_OldFormat(data).then(({ parsed_text, rich_text }) => {
-        if (parsed_text) {
-          const mergedData = parsed_text.paragraph_list.map((outerArr, i) =>
-            outerArr.map((innerArr, j) =>
-              innerArr.map((newItem, k) => {
-                const originalItem = this.data.paragraph_list[i]?.[j]?.[k];
-                // 唯一性校验:位置+内容哈希
-                const isSameItem =
-                  originalItem &&
-                  originalItem.hash === this.hashText(newItem.text) &&
-                  originalItem.id === `p${i}-l${j}-i${k}`;
-                if (!newItem.pinyin) newItem.pinyin = newItem.text;
-                let tmp = {
-                  ...newItem,
-                  id: `p${i}-l${j}-i${k}`,
-                  hash: this.hashText(newItem.text),
-                  ...(isSameItem && originalItem.activeTextStyle && { activeTextStyle: originalItem.activeTextStyle }),
-                };
-                if (styles) {
-                  if (!tmp.activeTextStyle) tmp.activeTextStyle = {};
-                  Object.assign(tmp.activeTextStyle, styles);
-                }
-                return tmp;
-              }),
-            ),
-          );
-          this.$set(this.data, 'paragraph_list', mergedData);
-          this.paragraphVersion += 1;
-          this.parseFClist(); // 确保在这里调用
-        }
-        this.$set(this.data, 'rich_text_list', rich_text.text_list);
-      });
+      this.loading = true;
+      await PinyinBuild_OldFormat(data)
+        .then(({ parsed_text, rich_text }) => {
+          this.loading = false;
+          if (parsed_text) {
+            const mergedData = parsed_text.paragraph_list.map((outerArr, i) =>
+              outerArr.map((innerArr, j) =>
+                innerArr.map((newItem, k) => {
+                  const originalItem = this.data.paragraph_list[i]?.[j]?.[k];
+                  // 唯一性校验:位置+内容哈希
+                  const isSameItem =
+                    originalItem &&
+                    originalItem.hash === this.hashText(newItem.text) &&
+                    originalItem.id === `p${i}-l${j}-i${k}`;
+                  if (!newItem.pinyin) newItem.pinyin = newItem.text;
+                  let tmp = {
+                    ...newItem,
+                    id: `p${i}-l${j}-i${k}`,
+                    hash: this.hashText(newItem.text),
+                    ...(isSameItem &&
+                      originalItem.activeTextStyle && { activeTextStyle: originalItem.activeTextStyle }),
+                  };
+                  if (styles) {
+                    if (!tmp.activeTextStyle) tmp.activeTextStyle = {};
+                    Object.assign(tmp.activeTextStyle, styles);
+                  }
+                  return tmp;
+                }),
+              ),
+            );
+            this.$set(this.data, 'paragraph_list', mergedData);
+            this.paragraphVersion += 1;
+            this.parseFClist(); // 确保在这里调用
+          }
+          this.$set(this.data, 'rich_text_list', rich_text.text_list);
+        })
+        .catch(() => {
+          this.loading = false;
+        });
     },
     // 开启拼音之后,拼音样式要跟随标题样式
     createParsedTextStyleForTitle(styles) {
@@ -555,7 +563,11 @@ export default {
       this.isViewExplanatoryNoteDialog = false;
     },
     // 设置备注
-    selectContentSetMemo(data) {
+    selectContentSetMemo(data, annota_id) {
+      if (annota_id) {
+        this.data.note_list = this.data.note_list.filter((p) => p.id !== annota_id && p.annota_id !== annota_id);
+        return;
+      }
       if (!data) return;
       // 统一 ID 字段,方便查找
       const currentId = data.annota_id || data.id;