zq vor 1 Woche
Ursprung
Commit
9b10c2bee9
2 geänderte Dateien mit 58 neuen und 21 gelöschten Zeilen
  1. 6 0
      src/components/CommonPreview.vue
  2. 52 21
      src/components/PinyinText.vue

+ 6 - 0
src/components/CommonPreview.vue

@@ -1142,6 +1142,12 @@ export default {
         const parser = new DOMParser();
         const doc = parser.parseFromString(html, 'text/html'); // 解析HTML字符串,返回Document对象
 
+        // 如果解析后只有一个 img 标签,直接返回原 HTML
+        const bodyChildren = doc.body.children;
+        if (bodyChildren.length === 1 && bodyChildren[0].tagName === 'IMG') {
+          return html;
+        }
+
         // 跳过 script 和 style 标签
         const skipTags = new Set(['SCRIPT', 'STYLE']);
 

+ 52 - 21
src/components/PinyinText.vue

@@ -36,7 +36,16 @@
             </span>
           </span>
         </span>
-
+        <!-- 图片块 -->
+        <img
+          v-else-if="block.type === 'image'"
+          :key="'image-' + index"
+          :src="block.src"
+          :alt="block.alt"
+          :width="block.width"
+          :height="block.height"
+          class="inline-image"
+        />
         <!-- 换行符 -->
         <br v-else-if="block.type === 'newline'" :key="'newline-' + index" />
       </template>
@@ -121,10 +130,12 @@ export default {
   props: {
     paragraphList: {
       type: Array,
+      default: () => [],
       required: false,
     },
     richTextList: {
       type: Array,
+      default: () => [],
       required: false,
     },
     pinyinPosition: {
@@ -141,6 +152,7 @@ export default {
     },
     pinyinSize: {
       type: String,
+      default: '',
     },
     pinyinOverallPosition: {
       type: String,
@@ -199,21 +211,34 @@ export default {
       let paragraphIndex = 0;
       const tagStack = [];
       for (const item of this.richTextList) {
-        oldIndex++;
-
-        if (item.is_style === 'true' || item.is_style === true) {
+        oldIndex += 1;
+
+        if (item.text && typeof item.text === 'string' && item.text.includes('<img')) {
+          // 处理图片
+          const imgMatch = item.text.match(/<img\s+([^>]*)\/?\s*>/i);
+          if (imgMatch) {
+            const attrs = imgMatch[1];
+            const srcMatch = attrs.match(/src=["']([^"']*)["']/i);
+            const altMatch = attrs.match(/alt=["']([^"']*)["']/i);
+            const widthMatch = attrs.match(/width=["']?(\d+)["']?/i);
+            const heightMatch = attrs.match(/height=["']?(\d+)["']?/i);
+
+            blocks.push({
+              type: 'image',
+              src: srcMatch ? srcMatch[1] : '',
+              alt: altMatch ? altMatch[1] : '',
+              width: widthMatch ? widthMatch[1] : null,
+              height: heightMatch ? heightMatch[1] : null,
+            });
+          }
+        } else if (item.is_style === 'true' || item.is_style === true) {
           const tagText = item.text || '';
           // 正则匹配闭标签:匹配 </tagname> 格式
           const closeTagMatch = tagText.match(/^<\/(\w+)>$/);
           if (closeTagMatch) {
             // 闭标签:从栈顶开始查找最近的同名标签并移除(LIFO 原则)
             const tagName = closeTagMatch[1];
-            for (let i = tagStack.length - 1; i >= 0; i--) {
-              if (tagStack[i].tag === tagName) {
-                tagStack.splice(i, 1);
-                break;
-              }
-            }
+            this.removeTagFromStack(tagStack, tagName);
           } else {
             // 开标签:解析标签名和样式并压栈
             const openTagMatch = tagText.match(/^<(\w+)([^>]*)>$/);
@@ -242,25 +267,23 @@ export default {
 
               tagStack.push({
                 tag: tagName,
-                style: style,
+                style,
               });
             }
           }
-        }
-        // 处理换行符
-        else if (item.text === '\n') {
+        } else if (item.text === '\n') {
+          // 处理换行符
           blocks.push({
             type: 'newline',
           });
           paragraphIndex++;
-        }
-        // 处理文字内容:将当前标签栈中的样式应用到文字块
-        else if (item.word_list && item.word_list.length > 0) {
+        } else if (item.word_list && item.word_list.length > 0) {
+          // 处理文字内容:将当前标签栈中的样式应用到文字块
           // 合并当前所有打开标签的样式
           let combinedStyle = '';
           tagStack.forEach((tagItem) => {
             if (tagItem.style) {
-              combinedStyle += tagItem.style + ';';
+              combinedStyle += `${tagItem.style};`;
             }
           });
 
@@ -284,9 +307,9 @@ export default {
             type: 'text',
             word_list: item.word_list,
             index: textBlockIndex++,
-            oldIndex: oldIndex,
-            paragraphIndex: paragraphIndex,
-            styleObj: styleObj, // 应用累积的样式对象
+            oldIndex,
+            paragraphIndex,
+            styleObj, // 应用累积的样式对象
           });
         }
       }
@@ -311,6 +334,14 @@ export default {
   },
 
   methods: {
+    removeTagFromStack(tagStack, tagName) {
+      for (let i = tagStack.length - 1; i >= 0; i--) {
+        if (tagStack[i].tag === tagName) {
+          tagStack.splice(i, 1);
+          break;
+        }
+      }
+    },
     textStyle(item) {
       const styles = { ...item.activeTextStyle };
       styles['font-size'] = styles.fontSize;