|
|
@@ -64,7 +64,7 @@
|
|
|
<!-- 延迟加载iframe:只有在可见且不是缩略图时才加载 -->
|
|
|
<iframe
|
|
|
:key="`html-${iframeKey}`"
|
|
|
- :srcdoc="elementInfo.url"
|
|
|
+ :srcdoc="processedSrcdoc"
|
|
|
v-else-if="elementInfo.isHTML && !isThumbnail && isVisible"
|
|
|
:width="width"
|
|
|
:height="height"
|
|
|
@@ -121,6 +121,10 @@ import {
|
|
|
} from '@/configs/englishSpeakingTools'
|
|
|
import { ref, watch, nextTick } from 'vue'
|
|
|
import { computed } from 'vue'
|
|
|
+import jqueryRaw from './jquery-3.6.0.min.js?raw'
|
|
|
+import awsSdkRaw from './aws-sdk-2.235.1.min.js?raw'
|
|
|
+import jietuRaw from './jietu.js?raw'
|
|
|
+import html2canvasRaw from 'html2canvas/dist/html2canvas.min.js?raw'
|
|
|
|
|
|
const props = defineProps({
|
|
|
elementInfo: {
|
|
|
@@ -144,6 +148,65 @@ const props = defineProps({
|
|
|
// 用于强制刷新iframe的key
|
|
|
const iframeKey = ref(0)
|
|
|
|
|
|
+// 处理 srcdoc:将页面自定义的 $ 改名为 _$,注入 jQuery 等脚本
|
|
|
+const processedSrcdoc = computed(() => {
|
|
|
+ if (!props.elementInfo.isHTML) return props.elementInfo.url
|
|
|
+
|
|
|
+ const html = props.elementInfo.url
|
|
|
+ try {
|
|
|
+ const parser = new DOMParser()
|
|
|
+ const doc = parser.parseFromString(html, 'text/html')
|
|
|
+
|
|
|
+ // 1. 重命名页面已有的 $ 变量为 _$,避免与 jQuery 冲突
|
|
|
+ // 支持 var/let/const 声明,以及 $(...) 调用和 $.xxx 属性访问
|
|
|
+ const scripts = doc.querySelectorAll('script:not([src])')
|
|
|
+ scripts.forEach(script => {
|
|
|
+ const content = script.textContent || ''
|
|
|
+ if (!content) return
|
|
|
+ const modified = content
|
|
|
+ // 重命名声明:var $ = / let $ = / const $ =
|
|
|
+ .replace(/\b(var|let|const)\s+\$\s*=/g, '$1 _$ =')
|
|
|
+ // 重命名调用:$('id') → _$('id')
|
|
|
+ .replace(/(^|[^a-zA-Z0-9_$])\$\s*\(/g, '$1_$(')
|
|
|
+ // 重命名属性访问:$.ajax → _$.ajax
|
|
|
+ .replace(/(^|[^a-zA-Z0-9_$])\$\./g, '$1_$.')
|
|
|
+ script.textContent = modified
|
|
|
+ })
|
|
|
+
|
|
|
+ // 2. 在 head 开头注入 jQuery、html2canvas、aws-sdk
|
|
|
+ const head = doc.head || doc.getElementsByTagName('head')[0] || doc.createElement('head')
|
|
|
+ if (!head.parentNode) {
|
|
|
+ doc.documentElement.insertBefore(head, doc.body || null)
|
|
|
+ }
|
|
|
+
|
|
|
+ const injectScript = (content: string, prepend = false) => {
|
|
|
+ const s = doc.createElement('script')
|
|
|
+ s.textContent = content
|
|
|
+ if (prepend) head.insertBefore(s, head.firstChild)
|
|
|
+ else head.appendChild(s)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 按顺序注入:jQuery → html2canvas → aws-sdk
|
|
|
+ injectScript(jqueryRaw, true)
|
|
|
+ injectScript(html2canvasRaw)
|
|
|
+ injectScript(awsSdkRaw)
|
|
|
+
|
|
|
+ // 3. 在 body 末尾追加 jietu.js(此时 $ 是 jQuery)
|
|
|
+ const body = doc.body || doc.getElementsByTagName('body')[0]
|
|
|
+ if (body) {
|
|
|
+ const jietuScript = doc.createElement('script')
|
|
|
+ jietuScript.textContent = jietuRaw
|
|
|
+ body.appendChild(jietuScript)
|
|
|
+ }
|
|
|
+
|
|
|
+ return '<!DOCTYPE html>' + doc.documentElement.outerHTML
|
|
|
+ }
|
|
|
+ catch (e) {
|
|
|
+ console.error('处理 srcdoc 失败:', e)
|
|
|
+ return html
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
// 监听elementInfo.url的变化
|
|
|
watch(
|
|
|
() => props.elementInfo.url,
|
|
|
@@ -198,78 +261,13 @@ const getTypeLabel = (type: number): string => {
|
|
|
|
|
|
const frameloading = ref(false)
|
|
|
|
|
|
-// 处理iframe加载完成事件
|
|
|
-const handleIframeLoad = async (event: Event) => {
|
|
|
- const iframe = event.target as HTMLIFrameElement
|
|
|
+// 处理iframe加载完成事件(脚本已在 srcdoc 中内联注入,这里只需隐藏 loading)
|
|
|
+const handleIframeLoad = async () => {
|
|
|
frameloading.value = true
|
|
|
- try {
|
|
|
- // 等待iframe完全加载
|
|
|
- await nextTick()
|
|
|
- setTimeout(async () => {
|
|
|
- // 检查iframe是否可访问(同源检查)
|
|
|
- if (iframe.contentWindow && iframe.contentDocument) {
|
|
|
- const iframeDoc = iframe.contentDocument
|
|
|
- const iframeHead =
|
|
|
- iframeDoc.head || iframeDoc.getElementsByTagName('head')[0]
|
|
|
-
|
|
|
- if (iframeHead) {
|
|
|
- // 使用动态导入获取JS文件内容
|
|
|
- const jsFiles = [
|
|
|
- {
|
|
|
- id: 'aws-sdk',
|
|
|
- importPath: () => import('./aws-sdk-2.235.1.min.js?raw'),
|
|
|
- },
|
|
|
- {
|
|
|
- id: 'jquery',
|
|
|
- importPath: () => import('./jquery-3.6.0.min.js?raw'),
|
|
|
- },
|
|
|
- { id: 'jietu', importPath: () => import('./jietu.js?raw') },
|
|
|
- ]
|
|
|
-
|
|
|
- for (const jsFile of jsFiles) {
|
|
|
- try {
|
|
|
- // 检查是否已经注入过
|
|
|
- if (!iframeDoc.getElementById(jsFile.id)) {
|
|
|
- const jsModule = await jsFile.importPath()
|
|
|
- const jsContent = jsModule.default || jsModule
|
|
|
-
|
|
|
- const scriptElement = iframeDoc.createElement('script')
|
|
|
- scriptElement.id = jsFile.id
|
|
|
- scriptElement.textContent = jsContent
|
|
|
- iframeHead.appendChild(scriptElement)
|
|
|
-
|
|
|
- console.log(`已注入 ${jsFile.id} 到iframe中`)
|
|
|
- }
|
|
|
- }
|
|
|
- catch (fetchError) {
|
|
|
- console.error(`获取 ${jsFile.id} 失败:`, fetchError)
|
|
|
- }
|
|
|
- }
|
|
|
- frameloading.value = false
|
|
|
-
|
|
|
- // 可选:在iframe中执行一些初始化代码
|
|
|
- try {
|
|
|
- iframe.contentWindow.eval(`
|
|
|
- console.log('iframe中的JS环境已准备就绪');
|
|
|
- // 这里可以添加一些初始化代码
|
|
|
- `)
|
|
|
- }
|
|
|
- catch (evalError) {
|
|
|
- frameloading.value = false
|
|
|
- console.warn('无法在iframe中执行代码:', evalError)
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- frameloading.value = false
|
|
|
- console.warn('无法访问iframe内容,可能是跨域限制')
|
|
|
- }
|
|
|
- }, 1000)
|
|
|
- }
|
|
|
- catch (error) {
|
|
|
+ await nextTick()
|
|
|
+ setTimeout(() => {
|
|
|
frameloading.value = false
|
|
|
- console.error('注入JS到iframe失败:', error)
|
|
|
- }
|
|
|
+ }, 500)
|
|
|
}
|
|
|
</script>
|
|
|
|
|
|
@@ -434,4 +432,4 @@ const handleIframeLoad = async (event: Event) => {
|
|
|
transform: rotate(360deg);
|
|
|
}
|
|
|
}
|
|
|
-</style>
|
|
|
+</style>
|